// See https://raw.githubusercontent.com/duckdb/duckdb/master/LICENSE for licensing information

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



#include <functional>





namespace duckdb {

class ClientContext;

//! The schema search path, in order by which entries are searched if no schema entry is provided
class CatalogSearchPath {
public:
	DUCKDB_API explicit CatalogSearchPath(ClientContext &client_p);
	CatalogSearchPath(const CatalogSearchPath &other) = delete;

	DUCKDB_API void Set(const string &new_value, bool is_set_schema);
	DUCKDB_API const vector<string> &Get();
	DUCKDB_API const vector<string> &GetSetPaths() {
		return set_paths;
	}
	DUCKDB_API const string &GetDefault();
	DUCKDB_API const string &GetOrDefault(const string &name);

private:
	static vector<string> ParsePaths(const string &value);

	void SetPaths(vector<string> new_paths);

private:
	ClientContext &context;
	vector<string> paths;
	//! Only the paths that were explicitly set (minus the always included paths)
	vector<string> set_paths;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry/aggregate_function_catalog_entry.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

//! An aggregate function in the catalog
class AggregateFunctionCatalogEntry : public StandardEntry {
public:
	AggregateFunctionCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateAggregateFunctionInfo *info)
	    : StandardEntry(CatalogType::AGGREGATE_FUNCTION_ENTRY, schema, catalog, info->name),
	      functions(info->functions.functions) {
	}

	//! The aggregate functions
	vector<AggregateFunction> functions;
};
} // namespace duckdb

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







namespace duckdb {

//! A collation catalog entry
class CollateCatalogEntry : public StandardEntry {
public:
	CollateCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateCollationInfo *info)
	    : StandardEntry(CatalogType::COLLATION_ENTRY, schema, catalog, info->name), function(info->function),
	      combinable(info->combinable), not_required_for_equality(info->not_required_for_equality) {
	}

	//! The collation function to push in case collation is required
	ScalarFunction function;
	//! Whether or not the collation can be combined with other collations.
	bool combinable;
	//! Whether or not the collation is required for equality comparisons or not. For many collations a binary
	//! comparison for equality comparisons is correct, allowing us to skip the collation in these cases which greatly
	//! speeds up processing.
	bool not_required_for_equality;
};
} // namespace duckdb

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







namespace duckdb {

class Catalog;
struct CreateCopyFunctionInfo;

//! A table function in the catalog
class CopyFunctionCatalogEntry : public StandardEntry {
public:
	CopyFunctionCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateCopyFunctionInfo *info);

	//! The copy function
	CopyFunction function;
};
} // namespace duckdb

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






namespace duckdb {

struct DataTableInfo;
class Index;

//! An index catalog entry
class IndexCatalogEntry : public StandardEntry {
public:
	//! Create a real TableCatalogEntry and initialize storage for it
	IndexCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateIndexInfo *info);
	~IndexCatalogEntry() override;

	Index *index;
	shared_ptr<DataTableInfo> info;
	string sql;

public:
	string ToSQL() override;
};

} // namespace duckdb

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






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








namespace duckdb {

//! A macro function in the catalog
class MacroCatalogEntry : public StandardEntry {
public:
	MacroCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateMacroInfo *info);
	//! The macro function
	unique_ptr<MacroFunction> function;

public:
	//! Serialize the meta information
	virtual void Serialize(Serializer &serializer) = 0;

	string ToSQL() override {
		return function->ToSQL(schema->name, name);
	}
};

} // namespace duckdb


namespace duckdb {

//! A macro function in the catalog
class ScalarMacroCatalogEntry : public MacroCatalogEntry {
public:
	ScalarMacroCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateMacroInfo *info);

public:
	//! Serialize the meta information of the ScalarMacroCatalogEntry
	void Serialize(Serializer &serializer) override;
	//! Deserializes to a CreateMacroInfo
	static unique_ptr<CreateMacroInfo> Deserialize(Deserializer &source);
};
} // namespace duckdb

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






namespace duckdb {

class Catalog;
struct CreatePragmaFunctionInfo;

//! A table function in the catalog
class PragmaFunctionCatalogEntry : public StandardEntry {
public:
	PragmaFunctionCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreatePragmaFunctionInfo *info);

	//! The pragma functions
	vector<PragmaFunction> functions;
};
} // namespace duckdb






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








namespace duckdb {

class DataTable;
struct CreateViewInfo;

//! A view catalog entry
class ViewCatalogEntry : public StandardEntry {
public:
	//! Create a real TableCatalogEntry and initialize storage for it
	ViewCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateViewInfo *info);

	//! The query of the view
	unique_ptr<SelectStatement> query;
	//! The SQL query (if any)
	string sql;
	//! The set of aliases associated with the view
	vector<string> aliases;
	//! The returned types of the view
	vector<LogicalType> types;

public:
	unique_ptr<CatalogEntry> AlterEntry(ClientContext &context, AlterInfo *info) override;

	//! Serialize the meta information of the ViewCatalogEntry a serializer
	virtual void Serialize(Serializer &serializer);
	//! Deserializes to a CreateTableInfo
	static unique_ptr<CreateViewInfo> Deserialize(Deserializer &source);

	unique_ptr<CatalogEntry> Copy(ClientContext &context) override;

	string ToSQL() override;

private:
	void Initialize(CreateViewInfo *info);
};
} // namespace duckdb

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





namespace duckdb {

class DefaultSchemaGenerator : public DefaultGenerator {
public:
	explicit DefaultSchemaGenerator(Catalog &catalog);

public:
	unique_ptr<CatalogEntry> CreateDefaultEntry(ClientContext &context, const string &entry_name) override;
	vector<string> GetDefaultEntries() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/dependency_manager.hpp
//
//
//===----------------------------------------------------------------------===//





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






namespace duckdb {
class CatalogEntry;

enum class DependencyType {
	DEPENDENCY_REGULAR = 0,
	DEPENDENCY_AUTOMATIC = 1,
	DEPENDENCY_OWNS = 2,
	DEPENDENCY_OWNED_BY = 3
};

struct Dependency {
	Dependency(CatalogEntry *entry, DependencyType dependency_type = DependencyType::DEPENDENCY_REGULAR)
	    : // NOLINT: Allow implicit conversion from `CatalogEntry`
	      entry(entry), dependency_type(dependency_type) {
	}

	//! The catalog entry this depends on
	CatalogEntry *entry;
	//! The type of dependency
	DependencyType dependency_type;
};

struct DependencyHashFunction {
	uint64_t operator()(const Dependency &a) const {
		std::hash<void *> hash_func;
		return hash_func((void *)a.entry);
	}
};

struct DependencyEquality {
	bool operator()(const Dependency &a, const Dependency &b) const {
		return a.entry == b.entry;
	}
};

using dependency_set_t = unordered_set<Dependency, DependencyHashFunction, DependencyEquality>;

} // namespace duckdb


#include <functional>

namespace duckdb {
class Catalog;
class ClientContext;

//! The DependencyManager is in charge of managing dependencies between catalog entries
class DependencyManager {
	friend class CatalogSet;

public:
	explicit DependencyManager(Catalog &catalog);

	//! Erase the object from the DependencyManager; this should only happen when the object itself is destroyed
	void EraseObject(CatalogEntry *object);

	//! Scans all dependencies, returning pairs of (object, dependent)
	void Scan(const std::function<void(CatalogEntry *, CatalogEntry *, DependencyType)> &callback);

	void AddOwnership(ClientContext &context, CatalogEntry *owner, CatalogEntry *entry);

private:
	Catalog &catalog;
	//! Map of objects that DEPEND on [object], i.e. [object] can only be deleted when all entries in the dependency map
	//! are deleted.
	unordered_map<CatalogEntry *, dependency_set_t> dependents_map;
	//! Map of objects that the source object DEPENDS on, i.e. when any of the entries in the vector perform a CASCADE
	//! drop then [object] is deleted as well
	unordered_map<CatalogEntry *, unordered_set<CatalogEntry *>> dependencies_map;

private:
	void AddObject(ClientContext &context, CatalogEntry *object, unordered_set<CatalogEntry *> &dependencies);
	void DropObject(ClientContext &context, CatalogEntry *object, bool cascade);
	void AlterObject(ClientContext &context, CatalogEntry *old_obj, CatalogEntry *new_obj);
	void EraseObjectInternal(CatalogEntry *object);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry/type_catalog_entry.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Serializer;
class Deserializer;

//! A type catalog entry
class TypeCatalogEntry : public StandardEntry {
public:
	//! Create a TypeCatalogEntry and initialize storage for it
	TypeCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateTypeInfo *info);

	LogicalType user_type;

public:
	//! Serialize the meta information of the TypeCatalogEntry a serializer
	virtual void Serialize(Serializer &serializer);
	//! Deserializes to a TypeCatalogEntry
	static unique_ptr<CreateTypeInfo> Deserialize(Deserializer &source);

	string ToSQL() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/client_data.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
class BufferedFileWriter;
class ClientContext;
class CatalogSearchPath;
class FileOpener;
class QueryProfiler;
class QueryProfilerHistory;
class PreparedStatementData;
class SchemaCatalogEntry;
struct RandomEngine;

struct ClientData {
	ClientData(ClientContext &context);
	~ClientData();

	//! Query profiler
	shared_ptr<QueryProfiler> profiler;
	//! QueryProfiler History
	unique_ptr<QueryProfilerHistory> query_profiler_history;

	//! The set of temporary objects that belong to this client
	unique_ptr<SchemaCatalogEntry> temporary_objects;
	//! The set of bound prepared statements that belong to this client
	unordered_map<string, shared_ptr<PreparedStatementData>> prepared_statements;

	//! The writer used to log queries (if logging is enabled)
	unique_ptr<BufferedFileWriter> log_query_writer;
	//! The random generator used by random(). Its seed value can be set by setseed().
	unique_ptr<RandomEngine> random_engine;

	//! The catalog search path
	const unique_ptr<CatalogSearchPath> catalog_search_path;

	//! The file opener of the client context
	unique_ptr<FileOpener> file_opener;

	//! The file search path
	string file_search_path;

public:
	DUCKDB_API static ClientData &Get(ClientContext &context);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/default/default_types.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class SchemaCatalogEntry;

class DefaultTypeGenerator : public DefaultGenerator {
public:
	DefaultTypeGenerator(Catalog &catalog, SchemaCatalogEntry *schema);

	SchemaCatalogEntry *schema;

public:
	DUCKDB_API static LogicalTypeId GetDefaultType(const string &name);

	unique_ptr<CatalogEntry> CreateDefaultEntry(ClientContext &context, const string &entry_name) override;
	vector<string> GetDefaultEntries() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/catalog_entry/macro_catalog_entry.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! A macro function in the catalog
class TableMacroCatalogEntry : public MacroCatalogEntry {
public:
	TableMacroCatalogEntry(Catalog *catalog, SchemaCatalogEntry *schema, CreateMacroInfo *info);

public:
	//! Serialize the meta information of the ScalarMacroCatalogEntry
	void Serialize(Serializer &serializer) override;
	//! Deserializes to a CreateMacroInfo
	static unique_ptr<CreateMacroInfo> Deserialize(Deserializer &source);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/field_writer.hpp
//
//
//===----------------------------------------------------------------------===//





#include <type_traits>

namespace duckdb {
class BufferedSerializer;

class FieldWriter {
public:
	FieldWriter(Serializer &serializer);
	~FieldWriter();

public:
	template <class T>
	void WriteField(const T &element) {
		static_assert(std::is_trivially_destructible<T>(), "WriteField object must be trivially destructible");

		AddField();
		WriteData((const_data_ptr_t)&element, sizeof(T));
	}

	//! Write a string with a length prefix
	void WriteString(const string &val) {
		WriteStringLen((const_data_ptr_t)val.c_str(), val.size());
	}
	void WriteStringLen(const_data_ptr_t val, idx_t len) {
		AddField();
		Write<uint32_t>((uint32_t)len);
		if (len > 0) {
			WriteData(val, len);
		}
	}
	void WriteBlob(const_data_ptr_t val, idx_t len) {
		AddField();
		if (len > 0) {
			WriteData(val, len);
		}
	}

	template <class T, class CONTAINER_TYPE = vector<T>>
	void WriteList(const CONTAINER_TYPE &elements) {
		AddField();
		Write<uint32_t>(elements.size());
		for (auto &element : elements) {
			Write<T>(element);
		}
	}

	template <class T>
	void WriteSerializable(const T &element) {
		AddField();
		element.Serialize(*buffer);
	}

	template <class T>
	void WriteSerializableList(const vector<unique_ptr<T>> &elements) {
		AddField();
		Write<uint32_t>(elements.size());
		for (idx_t i = 0; i < elements.size(); i++) {
			elements[i]->Serialize(*buffer);
		}
	}

	template <class T>
	void WriteRegularSerializableList(const vector<T> &elements) {
		AddField();
		Write<uint32_t>(elements.size());
		for (idx_t i = 0; i < elements.size(); i++) {
			elements[i].Serialize(*buffer);
		}
	}

	template <class T>
	void WriteOptional(const unique_ptr<T> &element) {
		AddField();
		Write<bool>(element ? true : false);
		if (element) {
			element->Serialize(*buffer);
		}
	}

	// Called after all fields have been written. Should always be called.
	void Finalize();

	Serializer &GetSerializer() {
		return *buffer;
	}

private:
	void AddField() {
		field_count++;
	}

	template <class T>
	void Write(const T &element) {
		WriteData((const_data_ptr_t)&element, sizeof(T));
	}

	void WriteData(const_data_ptr_t buffer, idx_t write_size);

private:
	Serializer &serializer;
	unique_ptr<BufferedSerializer> buffer;
	idx_t field_count;
	bool finalized;
};

template <>
void FieldWriter::Write(const string &val);

class FieldDeserializer : public Deserializer {
public:
	FieldDeserializer(Deserializer &root);

public:
	void ReadData(data_ptr_t buffer, idx_t read_size) override;

	void SetRemainingData(idx_t remaining_data);
	idx_t RemainingData();

private:
	Deserializer &root;
	idx_t remaining_data;
};

class FieldReader {
public:
	FieldReader(Deserializer &source);
	~FieldReader();

public:
	template <class T>
	T ReadRequired() {
		if (field_count >= max_field_count) {
			// field is not there, throw an exception
			throw SerializationException("Attempting to read a required field, but field is missing");
		}
		// field is there, read the actual value
		AddField();
		return source.Read<T>();
	}

	template <class T>
	T ReadField(T default_value) {
		if (field_count >= max_field_count) {
			// field is not there, read the default value
			return default_value;
		}
		// field is there, read the actual value
		AddField();
		return source.Read<T>();
	}

	template <class T>
	vector<T> ReadRequiredList() {
		if (field_count >= max_field_count) {
			// field is not there, throw an exception
			throw SerializationException("Attempting to read a required field, but field is missing");
		}
		AddField();
		auto result_count = source.Read<uint32_t>();
		vector<T> result;
		for (idx_t i = 0; i < result_count; i++) {
			result.push_back(source.Read<T>());
		}
		return result;
	}

	template <class T>
	unique_ptr<T> ReadOptional(unique_ptr<T> default_value) {
		if (field_count >= max_field_count) {
			// field is not there, read the default value
			return default_value;
		}
		// field is there, read the actual value
		AddField();
		return source.template ReadOptional<T>();
	}

	template <class T, class RETURN_TYPE = unique_ptr<T>>
	RETURN_TYPE ReadSerializable(RETURN_TYPE default_value) {
		if (field_count >= max_field_count) {
			// field is not there, read the default value
			return default_value;
		}
		// field is there, read the actual value
		AddField();
		return T::Deserialize(source);
	}

	template <class T, class RETURN_TYPE = unique_ptr<T>, typename... ARGS>
	RETURN_TYPE ReadSerializable(RETURN_TYPE default_value, ARGS &&...args) {
		if (field_count >= max_field_count) {
			// field is not there, read the default value
			return default_value;
		}
		// field is there, read the actual value
		AddField();
		return T::Deserialize(source, std::forward<ARGS>(args)...);
	}

	template <class T, class RETURN_TYPE = unique_ptr<T>>
	RETURN_TYPE ReadRequiredSerializable() {
		if (field_count >= max_field_count) {
			// field is not there, read the default value
			throw SerializationException("Attempting to read mandatory field, but field is missing");
		}
		// field is there, read the actual value
		AddField();
		return T::Deserialize(source);
	}

	template <class T, class RETURN_TYPE = unique_ptr<T>, typename... ARGS>
	RETURN_TYPE ReadRequiredSerializable(ARGS &&...args) {
		if (field_count >= max_field_count) {
			// field is not there, read the default value
			throw SerializationException("Attempting to read mandatory field, but field is missing");
		}
		// field is there, read the actual value
		AddField();
		return T::Deserialize(source, std::forward<ARGS>(args)...);
	}

	template <class T, class RETURN_TYPE = unique_ptr<T>>
	vector<RETURN_TYPE> ReadRequiredSerializableList() {
		if (field_count >= max_field_count) {
			// field is not there, read the default value
			throw SerializationException("Attempting to read mandatory field, but field is missing");
		}
		// field is there, read the actual value
		AddField();
		auto result_count = source.Read<uint32_t>();

		vector<RETURN_TYPE> result;
		for (idx_t i = 0; i < result_count; i++) {
			result.push_back(T::Deserialize(source));
		}
		return result;
	}
	void ReadBlob(data_ptr_t result, idx_t read_size) {
		if (field_count >= max_field_count) {
			// field is not there, throw an exception
			throw SerializationException("Attempting to read a required field, but field is missing");
		}
		// field is there, read the actual value
		AddField();
		source.ReadData(result, read_size);
	}

	//! Called after all fields have been read. Should always be called.
	void Finalize();

	Deserializer &GetSource() {
		return source;
	}

private:
	void AddField() {
		field_count++;
	}

private:
	FieldDeserializer source;
	idx_t field_count;
	idx_t max_field_count;
	idx_t total_size;
	bool finalized;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar_macro_function.hpp
//
//
//===----------------------------------------------------------------------===//


//! The SelectStatement of the view








namespace duckdb {

class ScalarMacroFunction : public MacroFunction {
public:
	ScalarMacroFunction(unique_ptr<ParsedExpression> expression);

	ScalarMacroFunction(void);
	//! The macro expression
	unique_ptr<ParsedExpression> expression;

public:
	unique_ptr<MacroFunction> Copy() override;

	string ToSQL(const string &schema, const string &name) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table_macro_function.hpp
//
//
//===----------------------------------------------------------------------===//











namespace duckdb {

class TableMacroFunction : public MacroFunction {
public:
	TableMacroFunction(unique_ptr<QueryNode> query_node);
	TableMacroFunction(void);

	//! The main query node
	unique_ptr<QueryNode> query_node;

public:
	unique_ptr<MacroFunction> Copy() override;

	string ToSQL(const string &schema, const string &name) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/default/default_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class SchemaCatalogEntry;

struct DefaultMacro {
	const char *schema;
	const char *name;
	const char *parameters[8];
	const char *macro;
};

class DefaultFunctionGenerator : public DefaultGenerator {
public:
	DefaultFunctionGenerator(Catalog &catalog, SchemaCatalogEntry *schema);

	SchemaCatalogEntry *schema;

	DUCKDB_API static unique_ptr<CreateMacroInfo> CreateInternalMacroInfo(DefaultMacro &default_macro);
	DUCKDB_API static unique_ptr<CreateMacroInfo> CreateInternalTableMacroInfo(DefaultMacro &default_macro);

public:
	unique_ptr<CatalogEntry> CreateDefaultEntry(ClientContext &context, const string &entry_name) override;
	vector<string> GetDefaultEntries() override;

private:
	static unique_ptr<CreateMacroInfo> CreateInternalTableMacroInfo(DefaultMacro &default_macro,
	                                                                unique_ptr<MacroFunction> function);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/catalog/default/default_views.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class SchemaCatalogEntry;

class DefaultViewGenerator : public DefaultGenerator {
public:
	DefaultViewGenerator(Catalog &catalog, SchemaCatalogEntry *schema);

	SchemaCatalogEntry *schema;

public:
	unique_ptr<CatalogEntry> CreateDefaultEntry(ClientContext &context, const string &entry_name) override;
	vector<string> GetDefaultEntries() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/constraints/bound_foreign_key_constraint.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class BoundForeignKeyConstraint : public BoundConstraint {
public:
	BoundForeignKeyConstraint(ForeignKeyInfo info_p, unordered_set<idx_t> pk_key_set_p,
	                          unordered_set<idx_t> fk_key_set_p)
	    : BoundConstraint(ConstraintType::FOREIGN_KEY), info(move(info_p)), pk_key_set(move(pk_key_set_p)),
	      fk_key_set(move(fk_key_set_p)) {
#ifdef DEBUG
		D_ASSERT(info.pk_keys.size() == pk_key_set.size());
		for (auto &key : info.pk_keys) {
			D_ASSERT(pk_key_set.find(key) != pk_key_set.end());
		}
		D_ASSERT(info.fk_keys.size() == fk_key_set.size());
		for (auto &key : info.fk_keys) {
			D_ASSERT(fk_key_set.find(key) != fk_key_set.end());
		}
#endif
	}

	ForeignKeyInfo info;
	//! The same keys but stored as an unordered set
	unordered_set<idx_t> pk_key_set;
	//! The same keys but stored as an unordered set
	unordered_set<idx_t> fk_key_set;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/constraints/foreign_key_constraint.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class ForeignKeyConstraint : public Constraint {
public:
	DUCKDB_API ForeignKeyConstraint(vector<string> pk_columns, vector<string> fk_columns, ForeignKeyInfo info);

	//! The set of main key table's columns
	vector<string> pk_columns;
	//! The set of foreign key table's columns
	vector<string> fk_columns;
	ForeignKeyInfo info;

public:
	DUCKDB_API string ToString() const override;

	DUCKDB_API unique_ptr<Constraint> Copy() const override;

	//! Serialize to a stand-alone binary blob
	DUCKDB_API void Serialize(FieldWriter &writer) const override;
	//! Deserializes a ParsedConstraint
	DUCKDB_API static unique_ptr<Constraint> Deserialize(FieldReader &source);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/algorithm.hpp
//
//
//===----------------------------------------------------------------------===//



#include <algorithm>
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/constraints/check_constraint.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! The CheckConstraint contains an expression that must evaluate to TRUE for
//! every row in a table
class CheckConstraint : public Constraint {
public:
	DUCKDB_API explicit CheckConstraint(unique_ptr<ParsedExpression> expression);

	unique_ptr<ParsedExpression> expression;

public:
	DUCKDB_API string ToString() const override;

	DUCKDB_API unique_ptr<Constraint> Copy() const override;

	DUCKDB_API void Serialize(FieldWriter &writer) const override;
	DUCKDB_API static unique_ptr<Constraint> Deserialize(FieldReader &source);
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/constraints/unique_constraint.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class UniqueConstraint : public Constraint {
public:
	DUCKDB_API UniqueConstraint(uint64_t index, bool is_primary_key);
	DUCKDB_API UniqueConstraint(vector<string> columns, bool is_primary_key);

	//! The index of the column for which this constraint holds. Only used when the constraint relates to a single
	//! column, equal to DConstants::INVALID_INDEX if not used
	uint64_t index;
	//! The set of columns for which this constraint holds by name. Only used when the index field is not used.
	vector<string> columns;
	//! Whether or not this is a PRIMARY KEY constraint, or a UNIQUE constraint.
	bool is_primary_key;

public:
	DUCKDB_API string ToString() const override;

	DUCKDB_API unique_ptr<Constraint> Copy() const override;

	//! Serialize to a stand-alone binary blob
	DUCKDB_API void Serialize(FieldWriter &writer) const override;
	//! Deserializes a ParsedConstraint
	DUCKDB_API static unique_ptr<Constraint> Deserialize(FieldReader &source);
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/constraints/bound_not_null_constraint.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class BoundNotNullConstraint : public BoundConstraint {
public:
	explicit BoundNotNullConstraint(column_t index) : BoundConstraint(ConstraintType::NOT_NULL), index(index) {
	}

	//! Column index this constraint pertains to
	storage_t index;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/constraints/bound_unique_constraint.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class BoundUniqueConstraint : public BoundConstraint {
public:
	BoundUniqueConstraint(vector<idx_t> keys, unordered_set<idx_t> key_set, bool is_primary_key)
	    : BoundConstraint(ConstraintType::UNIQUE), keys(move(keys)), key_set(move(key_set)),
	      is_primary_key(is_primary_key) {
#ifdef DEBUG
		D_ASSERT(keys.size() == key_set.size());
		for (auto &key : keys) {
			D_ASSERT(key_set.find(key) != key_set.end());
		}
#endif
	}

	//! The keys that define the unique constraint
	vector<idx_t> keys;
	//! The same keys but stored as an unordered set
	unordered_set<idx_t> key_set;
	//! Whether or not the unique constraint is a primary key
	bool is_primary_key;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/constraints/bound_check_constraint.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! The CheckConstraint contains an expression that must evaluate to TRUE for
//! every row in a table
class BoundCheckConstraint : public BoundConstraint {
public:
	BoundCheckConstraint() : BoundConstraint(ConstraintType::CHECK) {
	}

	//! The expression
	unique_ptr<Expression> expression;
	//! The columns used by the CHECK constraint
	unordered_set<column_t> bound_columns;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/storage_manager.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/write_ahead_log.hpp
//
//
//===----------------------------------------------------------------------===//





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





namespace duckdb {

enum class WALType : uint8_t {
	INVALID = 0,
	// -----------------------------
	// Catalog
	// -----------------------------
	CREATE_TABLE = 1,
	DROP_TABLE = 2,

	CREATE_SCHEMA = 3,
	DROP_SCHEMA = 4,

	CREATE_VIEW = 5,
	DROP_VIEW = 6,

	CREATE_SEQUENCE = 8,
	DROP_SEQUENCE = 9,
	SEQUENCE_VALUE = 10,

	CREATE_MACRO = 11,
	DROP_MACRO = 12,

	CREATE_TYPE = 13,
	DROP_TYPE = 14,

	ALTER_INFO = 20,

	CREATE_TABLE_MACRO = 21,
	DROP_TABLE_MACRO = 22,

	// -----------------------------
	// Data
	// -----------------------------
	USE_TABLE = 25,
	INSERT_TUPLE = 26,
	DELETE_TUPLE = 27,
	UPDATE_TUPLE = 28,
	// -----------------------------
	// Flush
	// -----------------------------
	CHECKPOINT = 99,
	WAL_FLUSH = 100
};
}








namespace duckdb {

struct AlterInfo;

class BufferedSerializer;
class Catalog;
class DatabaseInstance;
class SchemaCatalogEntry;
class SequenceCatalogEntry;
class ScalarMacroCatalogEntry;
class ViewCatalogEntry;
class TypeCatalogEntry;
class TableCatalogEntry;
class Transaction;
class TransactionManager;

//! The WriteAheadLog (WAL) is a log that is used to provide durability. Prior
//! to committing a transaction it writes the changes the transaction made to
//! the database to the log, which can then be replayed upon startup in case the
//! server crashes or is shut down.
class WriteAheadLog {
public:
	explicit WriteAheadLog(DatabaseInstance &database);

	//! Whether or not the WAL has been initialized
	bool initialized;
	//! Skip writing to the WAL
	bool skip_writing;

public:
	//! Replay the WAL
	static bool Replay(DatabaseInstance &database, string &path);

	//! Initialize the WAL in the specified directory
	void Initialize(string &path);
	//! Returns the current size of the WAL in bytes
	int64_t GetWALSize();
	//! Gets the total bytes written to the WAL since startup
	idx_t GetTotalWritten();

	void WriteCreateTable(TableCatalogEntry *entry);
	void WriteDropTable(TableCatalogEntry *entry);

	void WriteCreateSchema(SchemaCatalogEntry *entry);
	void WriteDropSchema(SchemaCatalogEntry *entry);

	void WriteCreateView(ViewCatalogEntry *entry);
	void WriteDropView(ViewCatalogEntry *entry);

	void WriteCreateSequence(SequenceCatalogEntry *entry);
	void WriteDropSequence(SequenceCatalogEntry *entry);
	void WriteSequenceValue(SequenceCatalogEntry *entry, SequenceValue val);

	void WriteCreateMacro(ScalarMacroCatalogEntry *entry);
	void WriteDropMacro(ScalarMacroCatalogEntry *entry);

	void WriteCreateTableMacro(TableMacroCatalogEntry *entry);
	void WriteDropTableMacro(TableMacroCatalogEntry *entry);

	void WriteCreateType(TypeCatalogEntry *entry);
	void WriteDropType(TypeCatalogEntry *entry);
	//! Sets the table used for subsequent insert/delete/update commands
	void WriteSetTable(string &schema, string &table);

	void WriteAlter(AlterInfo &info);

	void WriteInsert(DataChunk &chunk);
	void WriteDelete(DataChunk &chunk);
	//! Write a single (sub-) column update to the WAL. Chunk must be a pair of (COL, ROW_ID).
	//! The column_path vector is a *path* towards a column within the table
	//! i.e. if we have a table with a single column S STRUCT(A INT, B INT)
	//! and we update the validity mask of "S.B"
	//! the column path is:
	//! 0 (first column of table)
	//! -> 1 (second subcolumn of struct)
	//! -> 0 (first subcolumn of INT)
	void WriteUpdate(DataChunk &chunk, const vector<column_t> &column_path);

	//! Truncate the WAL to a previous size, and clear anything currently set in the writer
	void Truncate(int64_t size);
	//! Delete the WAL file on disk. The WAL should not be used after this point.
	void Delete();
	void Flush();

	void WriteCheckpoint(block_id_t meta_block);

private:
	DatabaseInstance &database;
	unique_ptr<BufferedFileWriter> writer;
	string wal_path;
};

} // namespace duckdb


namespace duckdb {
class BlockManager;
class Catalog;
class DatabaseInstance;
class TransactionManager;
class TableCatalogEntry;

//! StorageManager is responsible for managing the physical storage of the
//! database on disk
class StorageManager {
public:
	StorageManager(DatabaseInstance &db, string path, bool read_only);
	~StorageManager();

	//! The BlockManager to read/store meta information and data in blocks
	unique_ptr<BlockManager> block_manager;
	//! The BufferManager of the database
	unique_ptr<BufferManager> buffer_manager;
	//! The database this storagemanager belongs to
	DatabaseInstance &db;

public:
	static StorageManager &GetStorageManager(ClientContext &context);
	static StorageManager &GetStorageManager(DatabaseInstance &db);

	//! Initialize a database or load an existing database from the given path
	void Initialize();
	//! Get the WAL of the StorageManager, returns nullptr if in-memory
	WriteAheadLog *GetWriteAheadLog() {
		return wal.initialized ? &wal : nullptr;
	}

	DatabaseInstance &GetDatabase() {
		return db;
	}

	void CreateCheckpoint(bool delete_wal = false, bool force_checkpoint = false);

	string GetDBPath() {
		return path;
	}
	bool InMemory();

private:
	//! Load the database from a directory
	void LoadDatabase();

	//! The path of the database
	string path;
	//! The WriteAheadLog of the storage manager
	WriteAheadLog wal;

	//! Whether or not the database is opened in read-only mode
	bool read_only;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/art.hpp
//
//
//===----------------------------------------------------------------------===//










//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/art_key.hpp
//
//
//===----------------------------------------------------------------------===//





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









#include <cfloat>
#include <cstring> // strlen() on Solaris
#include <limits.h>

namespace duckdb {

#define BSWAP16(x) ((uint16_t)((((uint16_t)(x)&0xff00) >> 8) | (((uint16_t)(x)&0x00ff) << 8)))

#define BSWAP32(x)                                                                                                     \
	((uint32_t)((((uint32_t)(x)&0xff000000) >> 24) | (((uint32_t)(x)&0x00ff0000) >> 8) |                               \
	            (((uint32_t)(x)&0x0000ff00) << 8) | (((uint32_t)(x)&0x000000ff) << 24)))

#define BSWAP64(x)                                                                                                     \
	((uint64_t)((((uint64_t)(x)&0xff00000000000000ull) >> 56) | (((uint64_t)(x)&0x00ff000000000000ull) >> 40) |        \
	            (((uint64_t)(x)&0x0000ff0000000000ull) >> 24) | (((uint64_t)(x)&0x000000ff00000000ull) >> 8) |         \
	            (((uint64_t)(x)&0x00000000ff000000ull) << 8) | (((uint64_t)(x)&0x0000000000ff0000ull) << 24) |         \
	            (((uint64_t)(x)&0x000000000000ff00ull) << 40) | (((uint64_t)(x)&0x00000000000000ffull) << 56)))

struct Radix {
public:
	static inline bool IsLittleEndian() {
		int n = 1;
		if (*(char *)&n == 1) {
			return true;
		} else {
			return false;
		}
	}

	template <class T>
	static inline void EncodeData(data_ptr_t dataptr, T value, bool is_little_endian) {
		throw NotImplementedException("Cannot create data from this type");
	}

	static inline void EncodeStringDataPrefix(data_ptr_t dataptr, string_t value, idx_t prefix_len) {
		auto len = value.GetSize();
		memcpy(dataptr, value.GetDataUnsafe(), MinValue(len, prefix_len));
		if (len < prefix_len) {
			memset(dataptr + len, '\0', prefix_len - len);
		}
	}

	static inline uint8_t FlipSign(uint8_t key_byte) {
		return key_byte ^ 128;
	}

	static inline uint32_t EncodeFloat(float x) {
		uint64_t buff;

		//! zero
		if (x == 0) {
			buff = 0;
			buff |= (1u << 31);
			return buff;
		}
		// nan
		if (Value::IsNan(x)) {
			return UINT_MAX;
		}
		//! infinity
		if (x > FLT_MAX) {
			return UINT_MAX - 1;
		}
		//! -infinity
		if (x < -FLT_MAX) {
			return 0;
		}
		buff = Load<uint32_t>((const_data_ptr_t)&x);
		if ((buff & (1u << 31)) == 0) { //! +0 and positive numbers
			buff |= (1u << 31);
		} else {          //! negative numbers
			buff = ~buff; //! complement 1
		}

		return buff;
	}

	static inline uint64_t EncodeDouble(double x) {
		uint64_t buff;
		//! zero
		if (x == 0) {
			buff = 0;
			buff += (1ull << 63);
			return buff;
		}
		// nan
		if (Value::IsNan(x)) {
			return ULLONG_MAX;
		}
		//! infinity
		if (x > DBL_MAX) {
			return ULLONG_MAX - 1;
		}
		//! -infinity
		if (x < -DBL_MAX) {
			return 0;
		}
		buff = Load<uint64_t>((const_data_ptr_t)&x);
		if (buff < (1ull << 63)) { //! +0 and positive numbers
			buff += (1ull << 63);
		} else {          //! negative numbers
			buff = ~buff; //! complement 1
		}
		return buff;
	}
};

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, bool value, bool is_little_endian) {
	Store<uint8_t>(value ? 1 : 0, dataptr);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, int8_t value, bool is_little_endian) {
	Store<uint8_t>(value, dataptr);
	dataptr[0] = FlipSign(dataptr[0]);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, int16_t value, bool is_little_endian) {
	Store<uint16_t>(is_little_endian ? BSWAP16(value) : value, dataptr);
	dataptr[0] = FlipSign(dataptr[0]);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, int32_t value, bool is_little_endian) {
	Store<uint32_t>(is_little_endian ? BSWAP32(value) : value, dataptr);
	dataptr[0] = FlipSign(dataptr[0]);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, int64_t value, bool is_little_endian) {
	Store<uint64_t>(is_little_endian ? BSWAP64(value) : value, dataptr);
	dataptr[0] = FlipSign(dataptr[0]);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, uint8_t value, bool is_little_endian) {
	Store<uint8_t>(value, dataptr);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, uint16_t value, bool is_little_endian) {
	Store<uint16_t>(is_little_endian ? BSWAP16(value) : value, dataptr);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, uint32_t value, bool is_little_endian) {
	Store<uint32_t>(is_little_endian ? BSWAP32(value) : value, dataptr);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, uint64_t value, bool is_little_endian) {
	Store<uint64_t>(is_little_endian ? BSWAP64(value) : value, dataptr);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, hugeint_t value, bool is_little_endian) {
	EncodeData<int64_t>(dataptr, value.upper, is_little_endian);
	EncodeData<uint64_t>(dataptr + sizeof(value.upper), value.lower, is_little_endian);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, float value, bool is_little_endian) {
	uint32_t converted_value = EncodeFloat(value);
	Store<uint32_t>(is_little_endian ? BSWAP32(converted_value) : converted_value, dataptr);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, double value, bool is_little_endian) {
	uint64_t converted_value = EncodeDouble(value);
	Store<uint64_t>(is_little_endian ? BSWAP64(converted_value) : converted_value, dataptr);
}

template <>
inline void Radix::EncodeData(data_ptr_t dataptr, interval_t value, bool is_little_endian) {
	EncodeData<int32_t>(dataptr, value.months, is_little_endian);
	dataptr += sizeof(value.months);
	EncodeData<int32_t>(dataptr, value.days, is_little_endian);
	dataptr += sizeof(value.days);
	EncodeData<int64_t>(dataptr, value.micros, is_little_endian);
}

} // namespace duckdb




namespace duckdb {

class Key {
public:
	Key(unique_ptr<data_t[]> data, idx_t len);

	idx_t len;
	unique_ptr<data_t[]> data;

public:
	template <class T>
	static inline unique_ptr<Key> CreateKey(T element, bool is_little_endian) {
		auto data = Key::CreateData<T>(element, is_little_endian);
		return make_unique<Key>(move(data), sizeof(element));
	}

	template <class T>
	static inline unique_ptr<Key> CreateKey(const Value &element, bool is_little_endian) {
		return CreateKey(element.GetValueUnsafe<T>(), is_little_endian);
	}

public:
	data_t &operator[](std::size_t i) {
		return data[i];
	}
	const data_t &operator[](std::size_t i) const {
		return data[i];
	}
	bool operator>(const Key &k) const;
	bool operator<(const Key &k) const;
	bool operator>=(const Key &k) const;
	bool operator==(const Key &k) const;

private:
	template <class T>
	static inline unique_ptr<data_t[]> CreateData(T value, bool is_little_endian) {
		auto data = unique_ptr<data_t[]>(new data_t[sizeof(value)]);
		Radix::EncodeData<T>(data.get(), value, is_little_endian);
		return data;
	}
};

template <>
unique_ptr<Key> Key::CreateKey(string_t value, bool is_little_endian);
template <>
unique_ptr<Key> Key::CreateKey(const char *value, bool is_little_endian);

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/leaf.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/node.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
enum class NodeType : uint8_t { N4 = 0, N16 = 1, N48 = 2, N256 = 3, NLeaf = 4 };

class ART;

class Node {
public:
	static const uint8_t EMPTY_MARKER = 48;

public:
	Node(ART &art, NodeType type, size_t compressed_prefix_size);
	virtual ~Node() {
	}

	//! length of the compressed path (prefix)
	uint32_t prefix_length;
	//! number of non-null children
	uint16_t count;
	//! node type
	NodeType type;
	//! compressed path (prefix)
	unique_ptr<uint8_t[]> prefix;

public:
	//! Get the position of a child corresponding exactly to the specific byte, returns DConstants::INVALID_INDEX if not
	//! exists
	virtual idx_t GetChildPos(uint8_t k) {
		return DConstants::INVALID_INDEX;
	}
	//! Get the position of the first child that is greater or equal to the specific byte, or DConstants::INVALID_INDEX
	//! if there are no children matching the criteria
	virtual idx_t GetChildGreaterEqual(uint8_t k, bool &equal) {
		throw InternalException("Unimplemented GetChildGreaterEqual for ARTNode");
	}
	//! Get the position of the biggest element in node
	virtual idx_t GetMin();
	//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position. if pos ==
	//! DConstants::INVALID_INDEX, then the first valid position in the node will be returned.
	virtual idx_t GetNextPos(idx_t pos) {
		return DConstants::INVALID_INDEX;
	}
	//! Get the child at the specified position in the node. pos should be between [0, count). Throws an assertion if
	//! the element is not found.
	virtual unique_ptr<Node> *GetChild(idx_t pos);

	//! Compare the key with the prefix of the node, return the number matching bytes
	static uint32_t PrefixMismatch(ART &art, Node *node, Key &key, uint64_t depth);
	//! Insert leaf into inner node
	static void InsertLeaf(ART &art, unique_ptr<Node> &node, uint8_t key, unique_ptr<Node> &new_node);
	//! Erase entry from node
	static void Erase(ART &art, unique_ptr<Node> &node, idx_t pos);

protected:
	//! Copies the prefix from the source to the destination node
	static void CopyPrefix(ART &art, Node *src, Node *dst);
};

} // namespace duckdb


namespace duckdb {

class Leaf : public Node {
public:
	Leaf(ART &art, unique_ptr<Key> value, row_t row_id);

	unique_ptr<Key> value;
	idx_t capacity;
	idx_t num_elements;

	row_t GetRowId(idx_t index) {
		return row_ids[index];
	}

public:
	void Insert(row_t row_id);
	void Remove(row_t row_id);

private:
	unique_ptr<row_t[]> row_ids;
};

} // namespace duckdb


//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/node4.hpp
//
//
//===----------------------------------------------------------------------===//




namespace duckdb {

class Node4 : public Node {
public:
	Node4(ART &art, size_t compression_length);

	uint8_t key[4];
	unique_ptr<Node> child[4];

public:
	//! Get position of a byte, returns -1 if not exists
	idx_t GetChildPos(uint8_t k) override;
	//! Get the position of the first child that is greater or equal to the specific byte, or DConstants::INVALID_INDEX
	//! if there are no children matching the criteria
	idx_t GetChildGreaterEqual(uint8_t k, bool &equal) override;
	//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
	idx_t GetNextPos(idx_t pos) override;
	//! Get Node4 Child
	unique_ptr<Node> *GetChild(idx_t pos) override;

	idx_t GetMin() override;

	//! Insert Leaf to the Node4
	static void Insert(ART &art, unique_ptr<Node> &node, uint8_t key_byte, unique_ptr<Node> &child);
	//! Remove Leaf from Node4
	static void Erase(ART &art, unique_ptr<Node> &node, int pos);
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/node16.hpp
//
//
//===----------------------------------------------------------------------===//




namespace duckdb {

class Node16 : public Node {
public:
	Node16(ART &art, size_t compression_lengthh);

	uint8_t key[16];
	unique_ptr<Node> child[16];

public:
	//! Get position of a byte, returns -1 if not exists
	idx_t GetChildPos(uint8_t k) override;
	//! Get the position of the first child that is greater or equal to the specific byte, or DConstants::INVALID_INDEX
	//! if there are no children matching the criteria
	idx_t GetChildGreaterEqual(uint8_t k, bool &equal) override;
	//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
	idx_t GetNextPos(idx_t pos) override;
	//! Get Node16 Child
	unique_ptr<Node> *GetChild(idx_t pos) override;

	idx_t GetMin() override;

	//! Insert node into Node16
	static void Insert(ART &art, unique_ptr<Node> &node, uint8_t key_byte, unique_ptr<Node> &child);
	//! Shrink to node 4
	static void Erase(ART &art, unique_ptr<Node> &node, int pos);
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/node48.hpp
//
//
//===----------------------------------------------------------------------===//




namespace duckdb {

class Node48 : public Node {
public:
	Node48(ART &art, size_t compression_length);

	uint8_t child_index[256];
	unique_ptr<Node> child[48];

public:
	//! Get position of a byte, returns -1 if not exists
	idx_t GetChildPos(uint8_t k) override;
	//! Get the position of the first child that is greater or equal to the specific byte, or DConstants::INVALID_INDEX
	//! if there are no children matching the criteria
	idx_t GetChildGreaterEqual(uint8_t k, bool &equal) override;
	//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
	idx_t GetNextPos(idx_t pos) override;
	//! Get Node48 Child
	unique_ptr<Node> *GetChild(idx_t pos) override;

	idx_t GetMin() override;

	//! Insert node in Node48
	static void Insert(ART &art, unique_ptr<Node> &node, uint8_t key_byte, unique_ptr<Node> &child);

	//! Shrink to node 16
	static void Erase(ART &art, unique_ptr<Node> &node, int pos);
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/index/art/node256.hpp
//
//
//===----------------------------------------------------------------------===//




namespace duckdb {

class Node256 : public Node {
public:
	Node256(ART &art, size_t compression_length);

	unique_ptr<Node> child[256];

public:
	//! Get position of a specific byte, returns DConstants::INVALID_INDEX if not exists
	idx_t GetChildPos(uint8_t k) override;
	//! Get the position of the first child that is greater or equal to the specific byte, or DConstants::INVALID_INDEX
	//! if there are no children matching the criteria
	idx_t GetChildGreaterEqual(uint8_t k, bool &equal) override;
	//! Get the next position in the node, or DConstants::INVALID_INDEX if there is no next position
	idx_t GetNextPos(idx_t pos) override;
	//! Get Node256 Child
	unique_ptr<Node> *GetChild(idx_t pos) override;

	idx_t GetMin() override;

	//! Insert node From Node256
	static void Insert(ART &art, unique_ptr<Node> &node, uint8_t key_byte, unique_ptr<Node> &child);

	//! Shrink to node 48
	static void Erase(ART &art, unique_ptr<Node> &node, int pos);
};
} // namespace duckdb


namespace duckdb {
struct IteratorEntry {
	IteratorEntry() {
	}
	IteratorEntry(Node *node, idx_t pos) : node(node), pos(pos) {
	}

	Node *node = nullptr;
	idx_t pos = 0;
};

struct Iterator {
	//! The current Leaf Node, valid if depth>0
	Leaf *node = nullptr;
	//! The current depth
	int32_t depth = 0;
	//! Stack, the size is determined at runtime
	vector<IteratorEntry> stack;

	bool start = false;

	void SetEntry(idx_t depth, IteratorEntry entry);
};

struct ARTIndexScanState : public IndexScanState {
	ARTIndexScanState() : checked(false), result_index(0) {
	}

	Value values[2];
	ExpressionType expressions[2];
	bool checked;
	vector<row_t> result_ids;
	Iterator iterator;
	//! Stores the current leaf
	Leaf *cur_leaf = nullptr;
	//! Offset to leaf
	idx_t result_index = 0;
};

enum VerifyExistenceType : uint8_t {
	APPEND = 0,    // for purpose to append into table
	APPEND_FK = 1, // for purpose to append into table has foreign key
	DELETE_FK = 2  // for purpose to delete from table related to foreign key
};

class ART : public Index {
public:
	ART(const vector<column_t> &column_ids, const vector<unique_ptr<Expression>> &unbound_expressions,
	    IndexConstraintType constraint_type);
	~ART() override;

	//! Root of the tree
	unique_ptr<Node> tree;
	//! True if machine is little endian
	bool is_little_endian;

public:
	//! Initialize a scan on the index with the given expression and column ids
	//! to fetch from the base table for a single predicate
	unique_ptr<IndexScanState> InitializeScanSinglePredicate(Transaction &transaction, Value value,
	                                                         ExpressionType expressionType) override;

	//! Initialize a scan on the index with the given expression and column ids
	//! to fetch from the base table for two predicates
	unique_ptr<IndexScanState> InitializeScanTwoPredicates(Transaction &transaction, Value low_value,
	                                                       ExpressionType low_expression_type, Value high_value,
	                                                       ExpressionType high_expression_type) override;

	//! Perform a lookup on the index
	bool Scan(Transaction &transaction, DataTable &table, IndexScanState &state, idx_t max_count,
	          vector<row_t> &result_ids) override;
	//! Append entries to the index
	bool Append(IndexLock &lock, DataChunk &entries, Vector &row_identifiers) override;
	//! Verify that data can be appended to the index
	void VerifyAppend(DataChunk &chunk) override;
	//! Verify that data can be appended to the index for foreign key constraint
	void VerifyAppendForeignKey(DataChunk &chunk, string *err_msg_ptr) override;
	//! Verify that data can be delete from the index for foreign key constraint
	void VerifyDeleteForeignKey(DataChunk &chunk, string *err_msg_ptr) override;
	//! Delete entries in the index
	void Delete(IndexLock &lock, DataChunk &entries, Vector &row_identifiers) override;
	//! Insert data into the index.
	bool Insert(IndexLock &lock, DataChunk &data, Vector &row_ids) override;

	bool SearchEqual(ARTIndexScanState *state, idx_t max_count, vector<row_t> &result_ids);
	//! Search Equal used for Joins that do not need to fetch data
	void SearchEqualJoinNoFetch(Value &equal_value, idx_t &result_size);

private:
	//! Insert a row id into a leaf node
	bool InsertToLeaf(Leaf &leaf, row_t row_id);
	//! Insert the leaf value into the tree
	bool Insert(unique_ptr<Node> &node, unique_ptr<Key> key, unsigned depth, row_t row_id);

	//! Erase element from leaf (if leaf has more than one value) or eliminate the leaf itself
	void Erase(unique_ptr<Node> &node, Key &key, unsigned depth, row_t row_id);

	//! Check if the key of the leaf is equal to the searched key
	bool LeafMatches(Node *node, Key &key, unsigned depth);

	//! Find the node with a matching key, optimistic version
	Node *Lookup(unique_ptr<Node> &node, Key &key, unsigned depth);

	//! Find the first node that is bigger (or equal to) a specific key
	bool Bound(unique_ptr<Node> &node, Key &key, Iterator &iterator, bool inclusive);

	//! Gets next node for range queries
	bool IteratorNext(Iterator &iter);

	bool SearchGreater(ARTIndexScanState *state, bool inclusive, idx_t max_count, vector<row_t> &result_ids);
	bool SearchLess(ARTIndexScanState *state, bool inclusive, idx_t max_count, vector<row_t> &result_ids);
	bool SearchCloseRange(ARTIndexScanState *state, bool left_inclusive, bool right_inclusive, idx_t max_count,
	                      vector<row_t> &result_ids);

private:
	template <bool HAS_BOUND, bool INCLUSIVE>
	bool IteratorScan(ARTIndexScanState *state, Iterator *it, Key *upper_bound, idx_t max_count,
	                  vector<row_t> &result_ids);

	void GenerateKeys(DataChunk &input, vector<unique_ptr<Key>> &keys);

	void VerifyExistence(DataChunk &chunk, VerifyExistenceType verify_type, string *err_msg_ptr = NULL);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/parsed_expression_iterator.hpp
//
//
//===----------------------------------------------------------------------===//






#include <functional>

namespace duckdb {

class ParsedExpressionIterator {
public:
	static void EnumerateChildren(const ParsedExpression &expression,
	                              const std::function<void(const ParsedExpression &child)> &callback);
	static void EnumerateChildren(ParsedExpression &expr, const std::function<void(ParsedExpression &child)> &callback);
	static void EnumerateChildren(ParsedExpression &expr,
	                              const std::function<void(unique_ptr<ParsedExpression> &child)> &callback);

	static void EnumerateTableRefChildren(TableRef &ref,
	                                      const std::function<void(unique_ptr<ParsedExpression> &child)> &callback);
	static void EnumerateQueryNodeChildren(QueryNode &node,
	                                       const std::function<void(unique_ptr<ParsedExpression> &child)> &callback);

	static void EnumerateQueryNodeModifiers(QueryNode &node,
	                                        const std::function<void(unique_ptr<ParsedExpression> &child)> &callback);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/alter_binder.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class TableCatalogEntry;

//! The ALTER binder is responsible for binding an expression within alter statements
class AlterBinder : public ExpressionBinder {
public:
	AlterBinder(Binder &binder, ClientContext &context, TableCatalogEntry &table, vector<column_t> &bound_columns,
	            LogicalType target_type);

	TableCatalogEntry &table;
	vector<column_t> &bound_columns;

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	BindResult BindColumn(ColumnRefExpression &expr);

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/transaction_manager.hpp
//
//
//===----------------------------------------------------------------------===//










namespace duckdb {

class ClientContext;
class Catalog;
struct ClientLockWrapper;
class DatabaseInstance;
class Transaction;

struct StoredCatalogSet {
	//! Stored catalog set
	unique_ptr<CatalogSet> stored_set;
	//! The highest active query number when the catalog set was stored; used for cleaning up
	transaction_t highest_active_query;
};

//! The Transaction Manager is responsible for creating and managing
//! transactions
class TransactionManager {
	friend struct CheckpointLock;

public:
	explicit TransactionManager(DatabaseInstance &db);
	~TransactionManager();

	//! Start a new transaction
	Transaction *StartTransaction(ClientContext &context);
	//! Commit the given transaction
	string CommitTransaction(ClientContext &context, Transaction *transaction);
	//! Rollback the given transaction
	void RollbackTransaction(Transaction *transaction);

	transaction_t GetQueryNumber() {
		return current_query_number++;
	}
	transaction_t LowestActiveId() {
		return lowest_active_id;
	}
	transaction_t LowestActiveStart() {
		return lowest_active_start;
	}

	void Checkpoint(ClientContext &context, bool force = false);

	static TransactionManager &Get(ClientContext &context);
	static TransactionManager &Get(DatabaseInstance &db);

private:
	bool CanCheckpoint(Transaction *current = nullptr);
	//! Remove the given transaction from the list of active transactions
	void RemoveTransaction(Transaction *transaction) noexcept;
	void LockClients(vector<ClientLockWrapper> &client_locks, ClientContext &context);

	//! The database instance
	DatabaseInstance &db;
	//! The current query number
	atomic<transaction_t> current_query_number;
	//! The current start timestamp used by transactions
	transaction_t current_start_timestamp;
	//! The current transaction ID used by transactions
	transaction_t current_transaction_id;
	//! The lowest active transaction id
	atomic<transaction_t> lowest_active_id;
	//! The lowest active transaction timestamp
	atomic<transaction_t> lowest_active_start;
	//! Set of currently running transactions
	vector<unique_ptr<Transaction>> active_transactions;
	//! Set of recently committed transactions
	vector<unique_ptr<Transaction>> recently_committed_transactions;
	//! Transactions awaiting GC
	vector<unique_ptr<Transaction>> old_transactions;
	//! Catalog sets
	vector<StoredCatalogSet> old_catalog_sets;
	//! The lock used for transaction operations
	mutex transaction_lock;

	bool thread_is_checkpointing;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/result_arrow_wrapper.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ResultArrowArrayStreamWrapper {
public:
	explicit ResultArrowArrayStreamWrapper(unique_ptr<QueryResult> result, idx_t batch_size);
	ArrowArrayStream stream;
	unique_ptr<QueryResult> result;
	std::string last_error;
	idx_t batch_size;
	vector<LogicalType> column_types;
	vector<string> column_names;
	string timezone_config;

private:
	static int MyStreamGetSchema(struct ArrowArrayStream *stream, struct ArrowSchema *out);
	static int MyStreamGetNext(struct ArrowArrayStream *stream, struct ArrowArray *out);
	static void MyStreamRelease(struct ArrowArrayStream *stream);
	static const char *MyStreamGetLastError(struct ArrowArrayStream *stream);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/checksum.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! Compute a checksum over a buffer of size size
uint64_t Checksum(uint8_t *buffer, size_t size);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/crypto/md5.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class MD5Context {
public:
	static constexpr idx_t MD5_HASH_LENGTH_BINARY = 16;
	static constexpr idx_t MD5_HASH_LENGTH_TEXT = 32;

public:
	MD5Context();

	void Add(const_data_ptr_t data, idx_t len) {
		MD5Update(data, len);
	}
	void Add(const char *data);
	void Add(string_t string) {
		MD5Update((const_data_ptr_t)string.GetDataUnsafe(), string.GetSize());
	}
	void Add(const string &data) {
		MD5Update((const_data_ptr_t)data.c_str(), data.size());
	}

	//! Write the 16-byte (binary) digest to the specified location
	void Finish(data_ptr_t out_digest);
	//! Write the 32-character digest (in hexadecimal format) to the specified location
	void FinishHex(char *out_digest);
	//! Returns the 32-character digest (in hexadecimal format) as a string
	string FinishHex();

private:
	void MD5Update(const_data_ptr_t data, idx_t len);
	static void DigestToBase16(const_data_ptr_t digest, char *zBuf);

	uint32_t buf[4];
	uint32_t bits[2];
	unsigned char in[64];
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #1
// See the end of this file for a list

/*
 Formatting library for C++

 Copyright (c) 2012 - present, Victor Zverovich

 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.

 --- Optional exception to the license ---

 As an exception, if, as a result of your compiling your source code, portions
 of this Software are embedded into a machine-executable object form of such
 source code, you may redistribute such embedded portions in such object form
 without including the above copyright and permission notices.
 */

#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #1
// See the end of this file for a list

// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.

#ifndef FMT_CORE_H_
#define FMT_CORE_H_

#include <cstdio>  // std::FILE
#include <cstring>
#include <iterator>
#include <string>
#include <type_traits>

// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 60102

#ifdef __has_feature
#  define FMT_HAS_FEATURE(x) __has_feature(x)
#else
#  define FMT_HAS_FEATURE(x) 0
#endif

#if defined(__has_include) && !defined(__INTELLISENSE__) && \
    !(defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1600)
#  define FMT_HAS_INCLUDE(x) __has_include(x)
#else
#  define FMT_HAS_INCLUDE(x) 0
#endif

#ifdef __has_cpp_attribute
#  define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#  define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif

#if defined(__GNUC__) && !defined(__clang__)
#  define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#else
#  define FMT_GCC_VERSION 0
#endif

#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#  define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
#else
#  define FMT_HAS_GXX_CXX11 0
#endif

#ifdef __NVCC__
#  define FMT_NVCC __NVCC__
#else
#  define FMT_NVCC 0
#endif

#ifdef _MSC_VER
#  define FMT_MSC_VER _MSC_VER
#else
#  define FMT_MSC_VER 0
#endif

// Check if relaxed C++14 constexpr is supported.
// GCC doesn't allow throw in constexpr until version 6 (bug 67371).
#ifndef FMT_USE_CONSTEXPR
#  define FMT_USE_CONSTEXPR                                           \
    (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
     (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) &&           \
        !FMT_NVCC
#endif
#if FMT_USE_CONSTEXPR
#  define FMT_CONSTEXPR constexpr
#  define FMT_CONSTEXPR_DECL constexpr
#else
#  define FMT_CONSTEXPR inline
#  define FMT_CONSTEXPR_DECL
#endif

#ifndef FMT_OVERRIDE
#  if FMT_HAS_FEATURE(cxx_override) || \
      (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
#    define FMT_OVERRIDE override
#  else
#    define FMT_OVERRIDE
#  endif
#endif

// Check if exceptions are disabled.
#ifndef FMT_EXCEPTIONS
#  if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
      FMT_MSC_VER && !_HAS_EXCEPTIONS
#    define FMT_EXCEPTIONS 0
#  else
#    define FMT_EXCEPTIONS 1
#  endif
#endif

// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
#ifndef FMT_USE_NOEXCEPT
#  define FMT_USE_NOEXCEPT 0
#endif

#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
    (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
#  define FMT_DETECTED_NOEXCEPT noexcept
#  define FMT_HAS_CXX11_NOEXCEPT 1
#else
#  define FMT_DETECTED_NOEXCEPT throw()
#  define FMT_HAS_CXX11_NOEXCEPT 0
#endif

#ifndef FMT_NOEXCEPT
#  if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT
#    define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
#  else
#    define FMT_NOEXCEPT
#  endif
#endif

// [[noreturn]] is disabled on MSVC because of bogus unreachable code warnings.
#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER
#  define FMT_NORETURN [[noreturn]]
#else
#  define FMT_NORETURN
#endif

#ifndef FMT_DEPRECATED
#  if (FMT_HAS_CPP_ATTRIBUTE(deprecated) && __cplusplus >= 201402L) || \
      FMT_MSC_VER >= 1900
#    define FMT_DEPRECATED [[deprecated]]
#  else
#    if defined(__GNUC__) || defined(__clang__)
#      define FMT_DEPRECATED __attribute__((deprecated))
#    elif FMT_MSC_VER
#      define FMT_DEPRECATED __declspec(deprecated)
#    else
#      define FMT_DEPRECATED /* deprecated */
#    endif
#  endif
#endif

// Workaround broken [[deprecated]] in the Intel compiler and NVCC.
#if defined(__INTEL_COMPILER) || FMT_NVCC
#  define FMT_DEPRECATED_ALIAS
#else
#  define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
#endif

#ifndef FMT_BEGIN_NAMESPACE
#  if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
      FMT_MSC_VER >= 1900
#    define FMT_INLINE_NAMESPACE inline namespace
#    define FMT_END_NAMESPACE \
      }                       \
      }
#  else
#    define FMT_INLINE_NAMESPACE namespace
#    define FMT_END_NAMESPACE \
      }                       \
      using namespace v6;     \
      }
#  endif
#  define FMT_BEGIN_NAMESPACE \
    namespace duckdb_fmt {           \
    FMT_INLINE_NAMESPACE v6 {
#endif

#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
#  ifdef FMT_EXPORT
#    define FMT_API __declspec(dllexport)
#  elif defined(FMT_SHARED)
#    define FMT_API __declspec(dllimport)
#    define FMT_EXTERN_TEMPLATE_API FMT_API
#  endif
#endif
#ifndef FMT_API
#  define FMT_API
#endif
#ifndef FMT_EXTERN_TEMPLATE_API
#  define FMT_EXTERN_TEMPLATE_API
#endif

#ifndef FMT_HEADER_ONLY
#  define FMT_EXTERN extern
#else
#  define FMT_EXTERN
#endif

// libc++ supports string_view in pre-c++17.
#if (FMT_HAS_INCLUDE(<string_view>) &&                       \
     (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
    (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
#  include <string_view>
#  define FMT_USE_STRING_VIEW
#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L
#  include <experimental/string_view>
#  define FMT_USE_EXPERIMENTAL_STRING_VIEW
#endif

FMT_BEGIN_NAMESPACE

// Implementations of enable_if_t and other types for pre-C++14 systems.
template <bool B, class T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <bool B> using bool_constant = std::integral_constant<bool, B>;
template <typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
template <typename T>
using remove_const_t = typename std::remove_const<T>::type;
template <typename T>
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;

struct monostate {};

// An enable_if helper to be used in template parameters which results in much
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0

namespace internal {

// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
template <typename... Ts> struct void_t_impl { using type = void; };

#ifndef FMT_ASSERT
#define FMT_ASSERT(condition, message)
#endif

#if defined(FMT_USE_STRING_VIEW)
template <typename Char> using std_string_view = std::basic_string_view<Char>;
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
template <typename Char>
using std_string_view = std::experimental::basic_string_view<Char>;
#else
template <typename T> struct std_string_view {};
#endif

#ifdef FMT_USE_INT128
// Do nothing.
#elif defined(__SIZEOF_INT128__)
#  define FMT_USE_INT128 1
using int128_t = __int128_t;
using uint128_t = __uint128_t;
#else
#  define FMT_USE_INT128 0
#endif
#if !FMT_USE_INT128
struct int128_t {};
struct uint128_t {};
#endif

// Casts a nonnegative integer to unsigned.
template <typename Int>
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
  FMT_ASSERT(value >= 0, "negative value");
  return static_cast<typename std::make_unsigned<Int>::type>(value);
}
}  // namespace internal

template <typename... Ts>
using void_t = typename internal::void_t_impl<Ts...>::type;

/**
  An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
  subset of the API. ``fmt::basic_string_view`` is used for format strings even
  if ``std::string_view`` is available to prevent issues when a library is
  compiled with a different ``-std`` option than the client code (which is not
  recommended).
 */
template <typename Char> class basic_string_view {
 private:
  const Char* data_;
  size_t size_;

 public:
  using char_type = Char;
  using iterator = const Char*;

  FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}

  /** Constructs a string reference object from a C string and a size. */
  FMT_CONSTEXPR basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
      : data_(s),
        size_(count) {}

  /**
    \rst
    Constructs a string reference object from a C string computing
    the size with ``std::char_traits<Char>::length``.
    \endrst
   */
  basic_string_view(const Char* s)
      : data_(s), size_(std::char_traits<Char>::length(s)) {}

  /** Constructs a string reference from a ``std::basic_string`` object. */
  template <typename Traits, typename Alloc>
  FMT_CONSTEXPR basic_string_view(
      const std::basic_string<Char, Traits, Alloc>& s) FMT_NOEXCEPT
      : data_(s.data()),
        size_(s.size()) {}

  template <
      typename S,
      FMT_ENABLE_IF(std::is_same<S, internal::std_string_view<Char>>::value)>
  FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()),
                                                      size_(s.size()) {}

  /** Returns a pointer to the string data. */
  FMT_CONSTEXPR const Char* data() const { return data_; }

  /** Returns the string size. */
  FMT_CONSTEXPR size_t size() const { return size_; }

  FMT_CONSTEXPR iterator begin() const { return data_; }
  FMT_CONSTEXPR iterator end() const { return data_ + size_; }

  FMT_CONSTEXPR const Char& operator[](size_t pos) const { return data_[pos]; }

  FMT_CONSTEXPR void remove_prefix(size_t n) {
    data_ += n;
    size_ -= n;
  }

  // Lexicographically compare this string reference to other.
  int compare(basic_string_view other) const {
    size_t str_size = size_ < other.size_ ? size_ : other.size_;
    int result = std::char_traits<Char>::compare(data_, other.data_, str_size);
    if (result == 0)
      result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
    return result;
  }

  friend bool operator==(basic_string_view lhs, basic_string_view rhs) {
    return lhs.compare(rhs) == 0;
  }
  friend bool operator!=(basic_string_view lhs, basic_string_view rhs) {
    return lhs.compare(rhs) != 0;
  }
  friend bool operator<(basic_string_view lhs, basic_string_view rhs) {
    return lhs.compare(rhs) < 0;
  }
  friend bool operator<=(basic_string_view lhs, basic_string_view rhs) {
    return lhs.compare(rhs) <= 0;
  }
  friend bool operator>(basic_string_view lhs, basic_string_view rhs) {
    return lhs.compare(rhs) > 0;
  }
  friend bool operator>=(basic_string_view lhs, basic_string_view rhs) {
    return lhs.compare(rhs) >= 0;
  }
};

using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>;

#ifndef __cpp_char8_t
// A UTF-8 code unit type.
enum char8_t : unsigned char {};
#endif

/** Specifies if ``T`` is a character type. Can be specialized by users. */
template <typename T> struct is_char : std::false_type {};
template <> struct is_char<char> : std::true_type {};
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<char8_t> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};

/**
  \rst
  Returns a string view of `s`. In order to add custom string type support to
  {fmt} provide an overload of `to_string_view` for it in the same namespace as
  the type for the argument-dependent lookup to work.

  **Example**::

    namespace my_ns {
    inline string_view to_string_view(const my_string& s) {
      return {s.data(), s.length()};
    }
    }
    std::string message = fmt::format(my_string("The answer is {}"), 42);
  \endrst
 */
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
inline basic_string_view<Char> to_string_view(const Char* s) {
  return s;
}

template <typename Char, typename Traits, typename Alloc>
inline basic_string_view<Char> to_string_view(
    const std::basic_string<Char, Traits, Alloc>& s) {
  return s;
}

template <typename Char>
inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
  return s;
}

template <typename Char,
          FMT_ENABLE_IF(!std::is_empty<internal::std_string_view<Char>>::value)>
inline basic_string_view<Char> to_string_view(
    internal::std_string_view<Char> s) {
  return s;
}

// A base class for compile-time strings. It is defined in the fmt namespace to
// make formatting functions visible via ADL, e.g. format(fmt("{}"), 42).
struct compile_string {};

template <typename S>
struct is_compile_string : std::is_base_of<compile_string, S> {};

template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
  return s;
}

namespace internal {
void to_string_view(...);
using duckdb_fmt::v6::to_string_view;

// Specifies whether S is a string type convertible to fmt::basic_string_view.
// It should be a constexpr function but MSVC 2017 fails to compile it in
// enable_if and MSVC 2015 fails to compile it as an alias template.
template <typename S>
struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
};

template <typename S, typename = void> struct char_t_impl {};
template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
  using result = decltype(to_string_view(std::declval<S>()));
  using type = typename result::char_type;
};

struct error_handler {
  FMT_CONSTEXPR error_handler() = default;
  FMT_CONSTEXPR error_handler(const error_handler&) = default;

  // This function is intentionally not constexpr to give a compile-time error.
  FMT_NORETURN FMT_API void on_error(const char* message);
};
}  // namespace internal

/** String's character type. */
template <typename S> using char_t = typename internal::char_t_impl<S>::type;

/**
  \rst
  Parsing context consisting of a format string range being parsed and an
  argument counter for automatic indexing.

  You can use one of the following type aliases for common character types:

  +-----------------------+-------------------------------------+
  | Type                  | Definition                          |
  +=======================+=====================================+
  | format_parse_context  | basic_format_parse_context<char>    |
  +-----------------------+-------------------------------------+
  | wformat_parse_context | basic_format_parse_context<wchar_t> |
  +-----------------------+-------------------------------------+
  \endrst
 */
template <typename Char, typename ErrorHandler = internal::error_handler>
class basic_format_parse_context : private ErrorHandler {
 private:
  basic_string_view<Char> format_str_;
  int next_arg_id_;

 public:
  using char_type = Char;
  using iterator = typename basic_string_view<Char>::iterator;

  explicit FMT_CONSTEXPR basic_format_parse_context(
      basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
      : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}

  /**
    Returns an iterator to the beginning of the format string range being
    parsed.
   */
  FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {
    return format_str_.begin();
  }

  /**
    Returns an iterator past the end of the format string range being parsed.
   */
  FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }

  /** Advances the begin iterator to ``it``. */
  FMT_CONSTEXPR void advance_to(iterator it) {
    format_str_.remove_prefix(internal::to_unsigned(it - begin()));
  }

  /**
    Reports an error if using the manual argument indexing; otherwise returns
    the next argument index and switches to the automatic indexing.
   */
  FMT_CONSTEXPR int next_arg_id() {
    if (next_arg_id_ >= 0) return next_arg_id_++;
    on_error("cannot switch from manual to automatic argument indexing");
    return 0;
  }

  /**
    Reports an error if using the automatic argument indexing; otherwise
    switches to the manual indexing.
   */
  FMT_CONSTEXPR void check_arg_id(int) {
    if (next_arg_id_ > 0)
      on_error("cannot switch from automatic to manual argument indexing");
    else
      next_arg_id_ = -1;
  }

  FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}

  FMT_CONSTEXPR void on_error(const char* message) {
    ErrorHandler::on_error(message);
  }

  FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
};

using format_parse_context = basic_format_parse_context<char>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;

template <typename Char, typename ErrorHandler = internal::error_handler>
using basic_parse_context FMT_DEPRECATED_ALIAS =
    basic_format_parse_context<Char, ErrorHandler>;
using parse_context FMT_DEPRECATED_ALIAS = basic_format_parse_context<char>;
using wparse_context FMT_DEPRECATED_ALIAS = basic_format_parse_context<wchar_t>;

template <typename Context> class basic_format_arg;
template <typename Context> class basic_format_args;

// A formatter for objects of type T.
template <typename T, typename Char = char, typename Enable = void>
struct formatter {
  // A deleted default constructor indicates a disabled formatter.
  formatter() = delete;
};

template <typename T, typename Char, typename Enable = void>
struct FMT_DEPRECATED convert_to_int
    : bool_constant<!std::is_arithmetic<T>::value &&
                    std::is_convertible<T, int>::value> {};

// Specifies if T has an enabled formatter specialization. A type can be
// formattable even if it doesn't have a formatter e.g. via a conversion.
template <typename T, typename Context>
using has_formatter =
    std::is_constructible<typename Context::template formatter_type<T>>;

namespace internal {

/** A contiguous memory buffer with an optional growing ability. */
template <typename T> class buffer {
 private:
  T* ptr_;
  std::size_t size_;
  std::size_t capacity_;

 protected:
  // Don't initialize ptr_ since it is not accessed to save a few cycles.
  buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}

  buffer(T* p = nullptr, std::size_t sz = 0, std::size_t cap = 0) FMT_NOEXCEPT
      : ptr_(p),
        size_(sz),
        capacity_(cap) {}

  /** Sets the buffer data and capacity. */
  void set(T* buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {
    ptr_ = buf_data;
    capacity_ = buf_capacity;
  }

  /** Increases the buffer capacity to hold at least *capacity* elements. */
  virtual void grow(std::size_t capacity) = 0;

 public:
  using value_type = T;
  using const_reference = const T&;

  buffer(const buffer&) = delete;
  void operator=(const buffer&) = delete;
  virtual ~buffer() = default;

  T* begin() FMT_NOEXCEPT { return ptr_; }
  T* end() FMT_NOEXCEPT { return ptr_ + size_; }

  /** Returns the size of this buffer. */
  std::size_t size() const FMT_NOEXCEPT { return size_; }

  /** Returns the capacity of this buffer. */
  std::size_t capacity() const FMT_NOEXCEPT { return capacity_; }

  /** Returns a pointer to the buffer data. */
  T* data() FMT_NOEXCEPT { return ptr_; }

  /** Returns a pointer to the buffer data. */
  const T* data() const FMT_NOEXCEPT { return ptr_; }

  /**
    Resizes the buffer. If T is a POD type new elements may not be initialized.
   */
  void resize(std::size_t new_size) {
    reserve(new_size);
    size_ = new_size;
  }

  /** Clears this buffer. */
  void clear() { size_ = 0; }

  /** Reserves space to store at least *capacity* elements. */
  void reserve(std::size_t new_capacity) {
    if (new_capacity > capacity_) grow(new_capacity);
  }

  void push_back(const T& value) {
    reserve(size_ + 1);
    ptr_[size_++] = value;
  }

  /** Appends data to the end of the buffer. */
  template <typename U> void append(const U* begin, const U* end);

  T& operator[](std::size_t index) { return ptr_[index]; }
  const T& operator[](std::size_t index) const { return ptr_[index]; }
};

// A container-backed buffer.
template <typename Container>
class container_buffer : public buffer<typename Container::value_type> {
 private:
  Container& container_;

 protected:
  void grow(std::size_t capacity) FMT_OVERRIDE {
    container_.resize(capacity);
    this->set(&container_[0], capacity);
  }

 public:
  explicit container_buffer(Container& c)
      : buffer<typename Container::value_type>(c.size()), container_(c) {}
};

// Extracts a reference to the container from back_insert_iterator.
template <typename Container>
inline Container& get_container(std::back_insert_iterator<Container> it) {
  using bi_iterator = std::back_insert_iterator<Container>;
  struct accessor : bi_iterator {
    accessor(bi_iterator iter) : bi_iterator(iter) {}
    using bi_iterator::container;
  };
  return *accessor(it).container;
}

template <typename T, typename Char = char, typename Enable = void>
struct fallback_formatter {
  fallback_formatter() = delete;
};

// Specifies if T has an enabled fallback_formatter specialization.
template <typename T, typename Context>
using has_fallback_formatter =
    std::is_constructible<fallback_formatter<T, typename Context::char_type>>;

template <typename Char> struct named_arg_base;
template <typename T, typename Char> struct named_arg;

enum type {
  none_type,
  named_arg_type,
  // Integer types should go first,
  int_type,
  uint_type,
  long_long_type,
  ulong_long_type,
  int128_type,
  uint128_type,
  bool_type,
  char_type,
  last_integer_type = char_type,
  // followed by floating-point types.
  float_type,
  double_type,
  long_double_type,
  last_numeric_type = long_double_type,
  cstring_type,
  string_type,
  pointer_type,
  custom_type
};

// Maps core type T to the corresponding type enum constant.
template <typename T, typename Char>
struct type_constant : std::integral_constant<type, custom_type> {};

#define FMT_TYPE_CONSTANT(Type, constant) \
  template <typename Char>                \
  struct type_constant<Type, Char> : std::integral_constant<type, constant> {}

FMT_TYPE_CONSTANT(const named_arg_base<Char>&, named_arg_type);
FMT_TYPE_CONSTANT(int, int_type);
FMT_TYPE_CONSTANT(unsigned, uint_type);
FMT_TYPE_CONSTANT(long long, long_long_type);
FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
FMT_TYPE_CONSTANT(int128_t, int128_type);
FMT_TYPE_CONSTANT(uint128_t, uint128_type);
FMT_TYPE_CONSTANT(bool, bool_type);
FMT_TYPE_CONSTANT(Char, char_type);
FMT_TYPE_CONSTANT(float, float_type);
FMT_TYPE_CONSTANT(double, double_type);
FMT_TYPE_CONSTANT(long double, long_double_type);
FMT_TYPE_CONSTANT(const Char*, cstring_type);
FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
FMT_TYPE_CONSTANT(const void*, pointer_type);

FMT_CONSTEXPR bool is_integral_type(type t) {
  FMT_ASSERT(t != named_arg_type, "invalid argument type");
  return t > none_type && t <= last_integer_type;
}

FMT_CONSTEXPR bool is_arithmetic_type(type t) {
  FMT_ASSERT(t != named_arg_type, "invalid argument type");
  return t > none_type && t <= last_numeric_type;
}

template <typename Char> struct string_value {
  const Char* data;
  std::size_t size;
};

template <typename Context> struct custom_value {
  using parse_context = basic_format_parse_context<typename Context::char_type>;
  const void* value;
  void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
};

// A formatting argument value.
template <typename Context> class value {
 public:
  using char_type = typename Context::char_type;

  union {
    int int_value;
    unsigned uint_value;
    long long long_long_value;
    unsigned long long ulong_long_value;
    int128_t int128_value;
    uint128_t uint128_value;
    bool bool_value;
    char_type char_value;
    float float_value;
    double double_value;
    long double long_double_value;
    const void* pointer;
    string_value<char_type> string;
    custom_value<Context> custom;
    const named_arg_base<char_type>* named_arg;
  };

  FMT_CONSTEXPR value(int val = 0) : int_value(val) {}
  FMT_CONSTEXPR value(unsigned val) : uint_value(val) {}
  value(long long val) : long_long_value(val) {}
  value(unsigned long long val) : ulong_long_value(val) {}
  value(int128_t val) : int128_value(val) {}
  value(uint128_t val) : uint128_value(val) {}
  value(float val) : float_value(val) {}
  value(double val) : double_value(val) {}
  value(long double val) : long_double_value(val) {}
  value(bool val) : bool_value(val) {}
  value(char_type val) : char_value(val) {}
  value(const char_type* val) { string.data = val; }
  value(basic_string_view<char_type> val) {
    string.data = val.data();
    string.size = val.size();
  }
  value(const void* val) : pointer(val) {}

  template <typename T> value(const T& val) {
    custom.value = &val;
    // Get the formatter type through the context to allow different contexts
    // have different extension points, e.g. `formatter<T>` for `format` and
    // `printf_formatter<T>` for `printf`.
    custom.format = format_custom_arg<
        T, conditional_t<has_formatter<T, Context>::value,
                         typename Context::template formatter_type<T>,
                         fallback_formatter<T, char_type>>>;
  }

  value(const named_arg_base<char_type>& val) { named_arg = &val; }

 private:
  // Formats an argument of a custom type, such as a user-defined class.
  template <typename T, typename Formatter>
  static void format_custom_arg(
      const void* arg, basic_format_parse_context<char_type>& parse_ctx,
      Context& ctx) {
    Formatter f;
    parse_ctx.advance_to(f.parse(parse_ctx));
    ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
  }
};

template <typename Context, typename T>
FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value);

// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
enum { long_short = sizeof(long) == sizeof(int) };
using long_type = conditional_t<long_short, int, long long>;
using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;

// Maps formatting arguments to core types.
template <typename Context> struct arg_mapper {
  using char_type = typename Context::char_type;

  FMT_CONSTEXPR int map(signed char val) { return val; }
  FMT_CONSTEXPR unsigned map(unsigned char val) { return val; }
  FMT_CONSTEXPR int map(short val) { return val; }
  FMT_CONSTEXPR unsigned map(unsigned short val) { return val; }
  FMT_CONSTEXPR int map(int val) { return val; }
  FMT_CONSTEXPR unsigned map(unsigned val) { return val; }
  FMT_CONSTEXPR long_type map(long val) { return val; }
  FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
  FMT_CONSTEXPR long long map(long long val) { return val; }
  FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
  FMT_CONSTEXPR int128_t map(int128_t val) { return val; }
  FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; }
  FMT_CONSTEXPR bool map(bool val) { return val; }

  template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
  FMT_CONSTEXPR char_type map(T val) {
    static_assert(
        std::is_same<T, char>::value || std::is_same<T, char_type>::value,
        "mixing character types is disallowed");
    return val;
  }

  FMT_CONSTEXPR float map(float val) { return val; }
  FMT_CONSTEXPR double map(double val) { return val; }
  FMT_CONSTEXPR long double map(long double val) { return val; }

  FMT_CONSTEXPR const char_type* map(char_type* val) { return val; }
  FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; }
  template <typename T, FMT_ENABLE_IF(is_string<T>::value)>
  FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
    static_assert(std::is_same<char_type, char_t<T>>::value,
                  "mixing character types is disallowed");
    return to_string_view(val);
  }
  template <typename T,
            FMT_ENABLE_IF(
                std::is_constructible<basic_string_view<char_type>, T>::value &&
                !is_string<T>::value)>
  FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
    return basic_string_view<char_type>(val);
  }
  template <
      typename T,
      FMT_ENABLE_IF(
          std::is_constructible<std_string_view<char_type>, T>::value &&
          !std::is_constructible<basic_string_view<char_type>, T>::value &&
          !is_string<T>::value && !has_formatter<T, Context>::value)>
  FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
    return std_string_view<char_type>(val);
  }
  FMT_CONSTEXPR const char* map(const signed char* val) {
    static_assert(std::is_same<char_type, char>::value, "invalid string type");
    return reinterpret_cast<const char*>(val);
  }
  FMT_CONSTEXPR const char* map(const unsigned char* val) {
    static_assert(std::is_same<char_type, char>::value, "invalid string type");
    return reinterpret_cast<const char*>(val);
  }

  FMT_CONSTEXPR const void* map(void* val) { return val; }
  FMT_CONSTEXPR const void* map(const void* val) { return val; }
  FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; }
  template <typename T> FMT_CONSTEXPR int map(const T*) {
    // Formatting of arbitrary pointers is disallowed. If you want to output
    // a pointer cast it to "void *" or "const void *". In particular, this
    // forbids formatting of "[const] volatile char *" which is printed as bool
    // by iostreams.
    static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
    return 0;
  }

  template <typename T,
            FMT_ENABLE_IF(std::is_enum<T>::value &&
                          !has_formatter<T, Context>::value &&
                          !has_fallback_formatter<T, Context>::value)>
  FMT_CONSTEXPR auto map(const T& val) -> decltype(
      map(static_cast<typename std::underlying_type<T>::type>(val))) {
    return map(static_cast<typename std::underlying_type<T>::type>(val));
  }
  template <
      typename T,
      FMT_ENABLE_IF(
          !is_string<T>::value && !is_char<T>::value &&
          !std::is_constructible<basic_string_view<char_type>, T>::value &&
          (has_formatter<T, Context>::value ||
           (has_fallback_formatter<T, Context>::value &&
            !std::is_constructible<std_string_view<char_type>, T>::value)))>
  FMT_CONSTEXPR const T& map(const T& val) {
    return val;
  }

  template <typename T>
  FMT_CONSTEXPR const named_arg_base<char_type>& map(
      const named_arg<T, char_type>& val) {
    auto arg = make_arg<Context>(val.value);
    std::memcpy(val.data, &arg, sizeof(arg));
    return val;
  }
};

// A type constant after applying arg_mapper<Context>.
template <typename T, typename Context>
using mapped_type_constant =
    type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())),
                  typename Context::char_type>;

enum { packed_arg_bits = 5 };
// Maximum number of arguments with packed types.
enum { max_packed_args = 63 / packed_arg_bits };
enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };

template <typename Context> class arg_map;
}  // namespace internal

// A formatting argument. It is a trivially copyable/constructible type to
// allow storage in basic_memory_buffer.
template <typename Context> class basic_format_arg {
 private:
  internal::value<Context> value_;
  internal::type type_;

  template <typename ContextType, typename T>
  friend FMT_CONSTEXPR basic_format_arg<ContextType> internal::make_arg(
      const T& value);

  template <typename Visitor, typename Ctx>
  friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
                                             const basic_format_arg<Ctx>& arg)
      -> decltype(vis(0));

  friend class basic_format_args<Context>;
  friend class internal::arg_map<Context>;

  using char_type = typename Context::char_type;

 public:
  class handle {
   public:
    explicit handle(internal::custom_value<Context> custom) : custom_(custom) {}

    void format(basic_format_parse_context<char_type>& parse_ctx,
                Context& ctx) const {
      custom_.format(custom_.value, parse_ctx, ctx);
    }

   private:
    internal::custom_value<Context> custom_;
  };

  FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {}

  FMT_CONSTEXPR explicit operator bool() const FMT_NOEXCEPT {
    return type_ != internal::none_type;
  }

  internal::type type() const { return type_; }

  bool is_integral() const { return internal::is_integral_type(type_); }
  bool is_arithmetic() const { return internal::is_arithmetic_type(type_); }
};

/**
  \rst
  Visits an argument dispatching to the appropriate visit method based on
  the argument type. For example, if the argument type is ``double`` then
  ``vis(value)`` will be called with the value of type ``double``.
  \endrst
 */
template <typename Visitor, typename Context>
FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
                                    const basic_format_arg<Context>& arg)
    -> decltype(vis(0)) {
  using char_type = typename Context::char_type;
  switch (arg.type_) {
  case internal::none_type:
    break;
  case internal::named_arg_type:
    FMT_ASSERT(false, "invalid argument type");
    break;
  case internal::int_type:
    return vis(arg.value_.int_value);
  case internal::uint_type:
    return vis(arg.value_.uint_value);
  case internal::long_long_type:
    return vis(arg.value_.long_long_value);
  case internal::ulong_long_type:
    return vis(arg.value_.ulong_long_value);
#if FMT_USE_INT128
  case internal::int128_type:
    return vis(arg.value_.int128_value);
  case internal::uint128_type:
    return vis(arg.value_.uint128_value);
#else
  case internal::int128_type:
  case internal::uint128_type:
    break;
#endif
  case internal::bool_type:
    return vis(arg.value_.bool_value);
  case internal::char_type:
    return vis(arg.value_.char_value);
  case internal::float_type:
    return vis(arg.value_.float_value);
  case internal::double_type:
    return vis(arg.value_.double_value);
  case internal::long_double_type:
    return vis(arg.value_.long_double_value);
  case internal::cstring_type:
    return vis(arg.value_.string.data);
  case internal::string_type:
    return vis(basic_string_view<char_type>(arg.value_.string.data,
                                            arg.value_.string.size));
  case internal::pointer_type:
    return vis(arg.value_.pointer);
  case internal::custom_type:
    return vis(typename basic_format_arg<Context>::handle(arg.value_.custom));
  }
  return vis(monostate());
}

namespace internal {
// A map from argument names to their values for named arguments.
template <typename Context> class arg_map {
 private:
  using char_type = typename Context::char_type;

  struct entry {
    basic_string_view<char_type> name;
    basic_format_arg<Context> arg;
  };

  entry* map_;
  unsigned size_;

  void push_back(value<Context> val) {
    const auto& named = *val.named_arg;
    map_[size_] = {named.name, named.template deserialize<Context>()};
    ++size_;
  }

 public:
  arg_map(const arg_map&) = delete;
  void operator=(const arg_map&) = delete;
  arg_map() : map_(nullptr), size_(0) {}
  void init(const basic_format_args<Context>& args);
  ~arg_map() { delete[] map_; }

  basic_format_arg<Context> find(basic_string_view<char_type> name) const {
    // The list is unsorted, so just return the first matching name.
    for (entry *it = map_, *end = map_ + size_; it != end; ++it) {
      if (it->name == name) return it->arg;
    }
    return {};
  }
};

// A type-erased reference to an std::locale to avoid heavy <locale> include.
class locale_ref {
 private:
  const void* locale_;  // A type-erased pointer to std::locale.

 public:
  locale_ref() : locale_(nullptr) {}
  template <typename Locale> explicit locale_ref(const Locale& loc);

  explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }

  template <typename Locale> Locale get() const;
};

template <typename> constexpr unsigned long long encode_types() { return 0; }

template <typename Context, typename Arg, typename... Args>
constexpr unsigned long long encode_types() {
  return mapped_type_constant<Arg, Context>::value |
         (encode_types<Context, Args...>() << packed_arg_bits);
}

template <typename Context, typename T>
FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
  basic_format_arg<Context> arg;
  arg.type_ = mapped_type_constant<T, Context>::value;
  arg.value_ = arg_mapper<Context>().map(value);
  return arg;
}

template <bool IS_PACKED, typename Context, typename T,
          FMT_ENABLE_IF(IS_PACKED)>
inline value<Context> make_arg(const T& val) {
  return arg_mapper<Context>().map(val);
}

template <bool IS_PACKED, typename Context, typename T,
          FMT_ENABLE_IF(!IS_PACKED)>
inline basic_format_arg<Context> make_arg(const T& value) {
  return make_arg<Context>(value);
}
}  // namespace internal

// Formatting context.
template <typename OutputIt, typename Char> class basic_format_context {
 public:
  /** The character type for the output. */
  using char_type = Char;

 private:
  OutputIt out_;
  basic_format_args<basic_format_context> args_;
  internal::arg_map<basic_format_context> map_;
  internal::locale_ref loc_;

 public:
  using iterator = OutputIt;
  using format_arg = basic_format_arg<basic_format_context>;
  template <typename T> using formatter_type = formatter<T, char_type>;

  basic_format_context(const basic_format_context&) = delete;
  void operator=(const basic_format_context&) = delete;
  /**
   Constructs a ``basic_format_context`` object. References to the arguments are
   stored in the object so make sure they have appropriate lifetimes.
   */
  basic_format_context(OutputIt out,
                       basic_format_args<basic_format_context> ctx_args,
                       internal::locale_ref loc = internal::locale_ref())
      : out_(out), args_(ctx_args), loc_(loc) {}

  format_arg arg(int id) const { return args_.get(id); }

  // Checks if manual indexing is used and returns the argument with the
  // specified name.
  format_arg arg(basic_string_view<char_type> name);

  internal::error_handler error_handler() { return {}; }
  void on_error(const char* message) { error_handler().on_error(message); }

  // Returns an iterator to the beginning of the output range.
  iterator out() { return out_; }

  // Advances the begin iterator to ``it``.
  void advance_to(iterator it) { out_ = it; }

  internal::locale_ref locale() { return loc_; }
};

template <typename Char>
using buffer_context =
    basic_format_context<std::back_insert_iterator<internal::buffer<Char>>,
                         Char>;
using format_context = buffer_context<char>;
using wformat_context = buffer_context<wchar_t>;

/**
  \rst
  An array of references to arguments. It can be implicitly converted into
  `~fmt::basic_format_args` for passing into type-erased formatting functions
  such as `~fmt::vformat`.
  \endrst
 */
template <typename Context, typename... Args> class format_arg_store {
 private:
  static const size_t num_args = sizeof...(Args);
  static const bool is_packed = num_args < internal::max_packed_args;

  using value_type = conditional_t<is_packed, internal::value<Context>,
                                   basic_format_arg<Context>>;

  // If the arguments are not packed, add one more element to mark the end.
  value_type data_[num_args + (num_args == 0 ? 1 : 0)];

  friend class basic_format_args<Context>;

 public:
  static constexpr unsigned long long types =
      is_packed ? internal::encode_types<Context, Args...>()
                : internal::is_unpacked_bit | num_args;

  format_arg_store(const Args&... args)
      : data_{internal::make_arg<is_packed, Context>(args)...} {}
};

/**
  \rst
  Constructs an `~fmt::format_arg_store` object that contains references to
  arguments and can be implicitly converted to `~fmt::format_args`. `Context`
  can be omitted in which case it defaults to `~fmt::context`.
  See `~fmt::arg` for lifetime considerations.
  \endrst
 */
template <typename Context = format_context, typename... Args>
inline format_arg_store<Context, Args...> make_format_args(
    const Args&... args) {
  return {args...};
}

/** Formatting arguments. */
template <typename Context> class basic_format_args {
 public:
  using size_type = int;
  using format_arg = basic_format_arg<Context>;

 private:
  // To reduce compiled code size per formatting function call, types of first
  // max_packed_args arguments are passed in the types_ field.
  unsigned long long types_;
  union {
    // If the number of arguments is less than max_packed_args, the argument
    // values are stored in values_, otherwise they are stored in args_.
    // This is done to reduce compiled code size as storing larger objects
    // may require more code (at least on x86-64) even if the same amount of
    // data is actually copied to stack. It saves ~10% on the bloat test.
    const internal::value<Context>* values_;
    const format_arg* args_;
  };

  bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; }

  internal::type type(int index) const {
    int shift = index * internal::packed_arg_bits;
    unsigned int mask = (1 << internal::packed_arg_bits) - 1;
    return static_cast<internal::type>((types_ >> shift) & mask);
  }

  friend class internal::arg_map<Context>;

  void set_data(const internal::value<Context>* values) { values_ = values; }
  void set_data(const format_arg* args) { args_ = args; }

  format_arg do_get(int index) const {
    format_arg arg;
    if (!is_packed()) {
      auto num_args = max_size();
      if (index < num_args) arg = args_[index];
      return arg;
    }
    if (index > internal::max_packed_args) return arg;
    arg.type_ = type(index);
    if (arg.type_ == internal::none_type) return arg;
    internal::value<Context>& val = arg.value_;
    val = values_[index];
    return arg;
  }

 public:
  basic_format_args() : types_(0) {}

  /**
   \rst
   Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
   \endrst
   */
  template <typename... Args>
  basic_format_args(const format_arg_store<Context, Args...>& store)
      : types_(store.types) {
    set_data(store.data_);
  }

  /**
   \rst
   Constructs a `basic_format_args` object from a dynamic set of arguments.
   \endrst
   */
  basic_format_args(const format_arg* args, int count)
      : types_(internal::is_unpacked_bit | internal::to_unsigned(count)) {
    set_data(args);
  }

  /** Returns the argument at specified index. */
  format_arg get(int index) const {
    format_arg arg = do_get(index);
    if (arg.type_ == internal::named_arg_type)
      arg = arg.value_.named_arg->template deserialize<Context>();
    return arg;
  }

  int max_size() const {
    unsigned long long max_packed = internal::max_packed_args;
    return static_cast<int>(is_packed() ? max_packed
                                        : types_ & ~internal::is_unpacked_bit);
  }
};

/** An alias to ``basic_format_args<context>``. */
// It is a separate type rather than an alias to make symbols readable.
struct format_args : basic_format_args<format_context> {
  template <typename... Args>
  format_args(Args&&... args)
      : basic_format_args<format_context>(std::forward<Args>(args)...) {}
};
struct wformat_args : basic_format_args<wformat_context> {
  template <typename... Args>
  wformat_args(Args&&... args)
      : basic_format_args<wformat_context>(std::forward<Args>(args)...) {}
};

template <typename Container> struct is_contiguous : std::false_type {};

template <typename Char>
struct is_contiguous<std::basic_string<Char>> : std::true_type {};

template <typename Char>
struct is_contiguous<internal::buffer<Char>> : std::true_type {};

namespace internal {

template <typename OutputIt>
struct is_contiguous_back_insert_iterator : std::false_type {};
template <typename Container>
struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
    : is_contiguous<Container> {};

template <typename Char> struct named_arg_base {
  basic_string_view<Char> name;

  // Serialized value<context>.
  mutable char data[sizeof(basic_format_arg<buffer_context<Char>>)];

  named_arg_base(basic_string_view<Char> nm) : name(nm) {}

  template <typename Context> basic_format_arg<Context> deserialize() const {
    basic_format_arg<Context> arg;
    std::memcpy(&arg, data, sizeof(basic_format_arg<Context>));
    return arg;
  }
};

template <typename T, typename Char> struct named_arg : named_arg_base<Char> {
  const T& value;

  named_arg(basic_string_view<Char> name, const T& val)
      : named_arg_base<Char>(name), value(val) {}
};

template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
inline void check_format_string(const S&) {
#if defined(FMT_ENFORCE_COMPILE_STRING)
  static_assert(is_compile_string<S>::value,
                "FMT_ENFORCE_COMPILE_STRING requires all format strings to "
                "utilize FMT_STRING() or fmt().");
#endif
}
template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
void check_format_string(S);

struct view {};
template <bool...> struct bool_pack;
template <bool... Args>
using all_true =
    std::is_same<bool_pack<Args..., true>, bool_pack<true, Args...>>;

template <typename... Args, typename S, typename Char = char_t<S>>
inline format_arg_store<buffer_context<Char>, remove_reference_t<Args>...>
make_args_checked(const S& format_str,
                  const remove_reference_t<Args>&... args) {
  static_assert(all_true<(!std::is_base_of<view, remove_reference_t<Args>>() ||
                          !std::is_reference<Args>())...>::value,
                "passing views as lvalues is disallowed");
  check_format_string<remove_const_t<remove_reference_t<Args>>...>(format_str);
  return {args...};
}

template <typename Char>
std::basic_string<Char> vformat(basic_string_view<Char> format_str,
                                basic_format_args<buffer_context<Char>> args);

template <typename Char>
typename buffer_context<Char>::iterator vformat_to(
    buffer<Char>& buf, basic_string_view<Char> format_str,
    basic_format_args<buffer_context<Char>> args);
}  // namespace internal

/**
  \rst
  Returns a named argument to be used in a formatting function.

  The named argument holds a reference and does not extend the lifetime
  of its arguments.
  Consequently, a dangling reference can accidentally be created.
  The user should take care to only pass this function temporaries when
  the named argument is itself a temporary, as per the following example.

  **Example**::

    fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
  \endrst
 */
template <typename S, typename T, typename Char = char_t<S>>
inline internal::named_arg<T, Char> arg(const S& name, const T& arg) {
  static_assert(internal::is_string<S>::value, "");
  return {name, arg};
}

// Disable nested named arguments, e.g. ``arg("a", arg("b", 42))``.
template <typename S, typename T, typename Char>
void arg(S, internal::named_arg<T, Char>) = delete;

/** Formats a string and writes the output to ``out``. */
// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
template <typename OutputIt, typename S, typename Char = char_t<S>,
          FMT_ENABLE_IF(
              internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
OutputIt vformat_to(OutputIt out, const S& format_str,
                    basic_format_args<buffer_context<Char>> args) {
  using container = remove_reference_t<decltype(internal::get_container(out))>;
  internal::container_buffer<container> buf((internal::get_container(out)));
  internal::vformat_to(buf, to_string_view(format_str), args);
  return out;
}

template <typename Container, typename S, typename... Args,
          FMT_ENABLE_IF(
              is_contiguous<Container>::value&& internal::is_string<S>::value)>
inline std::back_insert_iterator<Container> format_to(
    std::back_insert_iterator<Container> out, const S& format_str,
    Args&&... args) {
  return vformat_to(
      out, to_string_view(format_str),
      {internal::make_args_checked<Args...>(format_str, args...)});
}

template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
    const S& format_str, basic_format_args<buffer_context<Char>> args) {
  return internal::vformat(to_string_view(format_str), args);
}

/**
  \rst
  Formats arguments and returns the result as a string.

  **Example**::

    #include <fmt/core.h>
    std::string message = fmt::format("The answer is {}", 42);
  \endrst
*/
// Pass char_t as a default template parameter instead of using
// std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const S& format_str, Args&&... args) {
  return internal::vformat(
      to_string_view(format_str),
      {internal::make_args_checked<Args...>(format_str, args...)});
}

FMT_END_NAMESPACE

#endif  // FMT_CORE_H_


// LICENSE_CHANGE_END


#include <algorithm>
#include <cerrno>
#include <cmath>
#include <cstdint>
#include <limits>
#include <memory>
#include <stdexcept>

#ifdef __clang__
#  define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
#else
#  define FMT_CLANG_VERSION 0
#endif

#ifdef __INTEL_COMPILER
#  define FMT_ICC_VERSION __INTEL_COMPILER
#elif defined(__ICL)
#  define FMT_ICC_VERSION __ICL
#else
#  define FMT_ICC_VERSION 0
#endif

#ifdef __NVCC__
#  define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__)
#else
#  define FMT_CUDA_VERSION 0
#endif

#ifdef __has_builtin
#  define FMT_HAS_BUILTIN(x) __has_builtin(x)
#else
#  define FMT_HAS_BUILTIN(x) 0
#endif

#if FMT_HAS_CPP_ATTRIBUTE(fallthrough) && \
    (__cplusplus >= 201703 || FMT_GCC_VERSION != 0)
#  define FMT_FALLTHROUGH [[fallthrough]]
#else
#  define FMT_FALLTHROUGH
#endif

#ifndef FMT_THROW
#  if FMT_EXCEPTIONS
#    if FMT_MSC_VER
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Exception> inline void do_throw(const Exception& x) {
  // Silence unreachable code warnings in MSVC because these are nearly
  // impossible to fix in a generic code.
  volatile bool b = true;
  if (b) throw x;
}
}  // namespace internal
FMT_END_NAMESPACE
#      define FMT_THROW(x) internal::do_throw(x)
#    else
#      define FMT_THROW(x) throw x
#    endif
#  else
#    define FMT_THROW(x)              \
      do {                            \
        static_cast<void>(sizeof(x)); \
        FMT_ASSERT(false, "");        \
      } while (false)
#  endif
#endif

#ifndef FMT_USE_USER_DEFINED_LITERALS
// For Intel and NVIDIA compilers both they and the system gcc/msc support UDLs.
#  if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 ||      \
       FMT_MSC_VER >= 1900) &&                                              \
      (!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || FMT_ICC_VERSION >= 1500 || \
       FMT_CUDA_VERSION >= 700)
#    define FMT_USE_USER_DEFINED_LITERALS 1
#  else
#    define FMT_USE_USER_DEFINED_LITERALS 0
#  endif
#endif

#ifndef FMT_USE_UDL_TEMPLATE
#define FMT_USE_UDL_TEMPLATE 0
#endif

// __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519
#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER
#  define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
#endif
#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER
#  define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
#endif

// Some compilers masquerade as both MSVC and GCC-likes or otherwise support
// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the
// MSVC intrinsics if the clz and clzll builtins are not available.
#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED)
#  include <intrin.h>  // _BitScanReverse, _BitScanReverse64

FMT_BEGIN_NAMESPACE
namespace internal {
// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning.
#  ifndef __clang__
#    pragma intrinsic(_BitScanReverse)
#  endif
inline uint32_t clz(uint32_t x) {
  unsigned long r = 0;
  _BitScanReverse(&r, x);

  FMT_ASSERT(x != 0, "");
  // Static analysis complains about using uninitialized data
  // "r", but the only way that can happen is if "x" is 0,
  // which the callers guarantee to not happen.
#  pragma warning(suppress : 6102)
  return 31 - r;
}
#  define FMT_BUILTIN_CLZ(n) internal::clz(n)

#  if defined(_WIN64) && !defined(__clang__)
#    pragma intrinsic(_BitScanReverse64)
#  endif

inline uint32_t clzll(uint64_t x) {
  unsigned long r = 0;
#  ifdef _WIN64
  _BitScanReverse64(&r, x);
#  else
  // Scan the high 32 bits.
  if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) return 63 - (r + 32);

  // Scan the low 32 bits.
  _BitScanReverse(&r, static_cast<uint32_t>(x));
#  endif

  FMT_ASSERT(x != 0, "");
  // Static analysis complains about using uninitialized data
  // "r", but the only way that can happen is if "x" is 0,
  // which the callers guarantee to not happen.
#  pragma warning(suppress : 6102)
  return 63 - r;
}
#  define FMT_BUILTIN_CLZLL(n) internal::clzll(n)
}  // namespace internal
FMT_END_NAMESPACE
#endif

// Enable the deprecated numeric alignment.
#ifndef FMT_NUMERIC_ALIGN
#  define FMT_NUMERIC_ALIGN 1
#endif

// Enable the deprecated percent specifier.
#ifndef FMT_DEPRECATED_PERCENT
#  define FMT_DEPRECATED_PERCENT 0
#endif

FMT_BEGIN_NAMESPACE
namespace internal {

// A helper function to suppress bogus "conditional expression is constant"
// warnings.
template <typename T> inline T const_check(T value) { return value; }

// An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have
// undefined behavior (e.g. due to type aliasing).
// Example: uint64_t d = bit_cast<uint64_t>(2.718);
template <typename Dest, typename Source>
inline Dest bit_cast(const Source& source) {
  static_assert(sizeof(Dest) == sizeof(Source), "size mismatch");
  Dest dest;
  std::memcpy(&dest, &source, sizeof(dest));
  return dest;
}

inline bool is_big_endian() {
  auto u = 1u;
  struct bytes {
    char data[sizeof(u)];
  };
  return bit_cast<bytes>(u).data[0] == 0;
}

// A fallback implementation of uintptr_t for systems that lack it.
struct fallback_uintptr {
  unsigned char value[sizeof(void*)];

  fallback_uintptr() = default;
  explicit fallback_uintptr(const void* p) {
    *this = bit_cast<fallback_uintptr>(p);
    if (is_big_endian()) {
      for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j)
        std::swap(value[i], value[j]);
    }
  }
};
#ifdef UINTPTR_MAX
using uintptr_t = ::uintptr_t;
inline uintptr_t to_uintptr(const void* p) { return bit_cast<uintptr_t>(p); }
#else
using uintptr_t = fallback_uintptr;
inline fallback_uintptr to_uintptr(const void* p) {
  return fallback_uintptr(p);
}
#endif

// Returns the largest possible value for type T. Same as
// std::numeric_limits<T>::max() but shorter and not affected by the max macro.
template <typename T> constexpr T max_value() {
  return (std::numeric_limits<T>::max)();
}
template <typename T> constexpr int num_bits() {
  return std::numeric_limits<T>::digits;
}
template <> constexpr int num_bits<fallback_uintptr>() {
  return static_cast<int>(sizeof(void*) *
                          std::numeric_limits<unsigned char>::digits);
}

// An approximation of iterator_t for pre-C++20 systems.
template <typename T>
using iterator_t = decltype(std::begin(std::declval<T&>()));

// Detect the iterator category of *any* given type in a SFINAE-friendly way.
// Unfortunately, older implementations of std::iterator_traits are not safe
// for use in a SFINAE-context.
template <typename It, typename Enable = void>
struct iterator_category : std::false_type {};

template <typename T> struct iterator_category<T*> {
  using type = std::random_access_iterator_tag;
};

template <typename It>
struct iterator_category<It, void_t<typename It::iterator_category>> {
  using type = typename It::iterator_category;
};

// Detect if *any* given type models the OutputIterator concept.
template <typename It> class is_output_iterator {
  // Check for mutability because all iterator categories derived from
  // std::input_iterator_tag *may* also meet the requirements of an
  // OutputIterator, thereby falling into the category of 'mutable iterators'
  // [iterator.requirements.general] clause 4. The compiler reveals this
  // property only at the point of *actually dereferencing* the iterator!
  template <typename U>
  static decltype(*(std::declval<U>())) test(std::input_iterator_tag);
  template <typename U> static char& test(std::output_iterator_tag);
  template <typename U> static const char& test(...);

  using type = decltype(test<It>(typename iterator_category<It>::type{}));

 public:
  static const bool value = !std::is_const<remove_reference_t<type>>::value;
};

// A workaround for std::string not having mutable data() until C++17.
template <typename Char> inline Char* get_data(std::basic_string<Char>& s) {
  return &s[0];
}
template <typename Container>
inline typename Container::value_type* get_data(Container& c) {
  return c.data();
}

#ifdef _SECURE_SCL
// Make a checked iterator to avoid MSVC warnings.
template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>;
template <typename T> checked_ptr<T> make_checked(T* p, std::size_t size) {
  return {p, size};
}
#else
template <typename T> using checked_ptr = T*;
template <typename T> inline T* make_checked(T* p, std::size_t) { return p; }
#endif

template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
inline checked_ptr<typename Container::value_type> reserve(
    std::back_insert_iterator<Container>& it, std::size_t n) {
  Container& c = get_container(it);
  std::size_t size = c.size();
  c.resize(size + n);
  return make_checked(get_data(c) + size, n);
}

template <typename Iterator>
inline Iterator& reserve(Iterator& it, std::size_t) {
  return it;
}

// An output iterator that counts the number of objects written to it and
// discards them.
class counting_iterator {
 private:
  std::size_t count_;

 public:
  using iterator_category = std::output_iterator_tag;
  using difference_type = std::ptrdiff_t;
  using pointer = void;
  using reference = void;
  using _Unchecked_type = counting_iterator;  // Mark iterator as checked.

  struct value_type {
    template <typename T> void operator=(const T&) {}
  };

  counting_iterator() : count_(0) {}

  std::size_t count() const { return count_; }

  counting_iterator& operator++() {
    ++count_;
    return *this;
  }

  counting_iterator operator++(int) {
    auto it = *this;
    ++*this;
    return it;
  }

  value_type operator*() const { return {}; }
};

template <typename OutputIt> class truncating_iterator_base {
 protected:
  OutputIt out_;
  std::size_t limit_;
  std::size_t count_;

  truncating_iterator_base(OutputIt out, std::size_t limit)
      : out_(out), limit_(limit), count_(0) {}

 public:
  using iterator_category = std::output_iterator_tag;
  using difference_type = void;
  using pointer = void;
  using reference = void;
  using _Unchecked_type =
      truncating_iterator_base;  // Mark iterator as checked.

  OutputIt base() const { return out_; }
  std::size_t count() const { return count_; }
};

// An output iterator that truncates the output and counts the number of objects
// written to it.
template <typename OutputIt,
          typename Enable = typename std::is_void<
              typename std::iterator_traits<OutputIt>::value_type>::type>
class truncating_iterator;

template <typename OutputIt>
class truncating_iterator<OutputIt, std::false_type>
    : public truncating_iterator_base<OutputIt> {
  using traits = std::iterator_traits<OutputIt>;

  mutable typename traits::value_type blackhole_;

 public:
  using value_type = typename traits::value_type;

  truncating_iterator(OutputIt out, std::size_t limit)
      : truncating_iterator_base<OutputIt>(out, limit) {}

  truncating_iterator& operator++() {
    if (this->count_++ < this->limit_) ++this->out_;
    return *this;
  }

  truncating_iterator operator++(int) {
    auto it = *this;
    ++*this;
    return it;
  }

  value_type& operator*() const {
    return this->count_ < this->limit_ ? *this->out_ : blackhole_;
  }
};

template <typename OutputIt>
class truncating_iterator<OutputIt, std::true_type>
    : public truncating_iterator_base<OutputIt> {
 public:
  using value_type = typename OutputIt::container_type::value_type;

  truncating_iterator(OutputIt out, std::size_t limit)
      : truncating_iterator_base<OutputIt>(out, limit) {}

  truncating_iterator& operator=(value_type val) {
    if (this->count_++ < this->limit_) this->out_ = val;
    return *this;
  }

  truncating_iterator& operator++() { return *this; }
  truncating_iterator& operator++(int) { return *this; }
  truncating_iterator& operator*() { return *this; }
};

// A range with the specified output iterator and value type.
template <typename OutputIt, typename T = typename OutputIt::value_type>
class output_range {
 private:
  OutputIt it_;

 public:
  using value_type = T;
  using iterator = OutputIt;
  struct sentinel {};

  explicit output_range(OutputIt it) : it_(it) {}
  OutputIt begin() const { return it_; }
  sentinel end() const { return {}; }  // Sentinel is not used yet.
};

template <typename Char>
inline size_t count_code_points(basic_string_view<Char> s) {
  return s.size();
}

// Counts the number of code points in a UTF-8 string.
inline size_t count_code_points(basic_string_view<char8_t> s) {
  const char8_t* data = s.data();
  size_t num_code_points = 0;
  for (size_t i = 0, size = s.size(); i != size; ++i) {
    if ((data[i] & 0xc0) != 0x80) ++num_code_points;
  }
  return num_code_points;
}

template <typename Char>
inline size_t code_point_index(basic_string_view<Char> s, size_t n) {
  size_t size = s.size();
  return n < size ? n : size;
}

// Calculates the index of the nth code point in a UTF-8 string.
inline size_t code_point_index(basic_string_view<char8_t> s, size_t n) {
  const char8_t* data = s.data();
  size_t num_code_points = 0;
  for (size_t i = 0, size = s.size(); i != size; ++i) {
    if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) {
      return i;
    }
  }
  return s.size();
}

inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); }

template <typename InputIt, typename OutChar>
using needs_conversion = bool_constant<
    std::is_same<typename std::iterator_traits<InputIt>::value_type,
                 char>::value &&
    std::is_same<OutChar, char8_t>::value>;

template <typename OutChar, typename InputIt, typename OutputIt,
          FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
  return std::copy(begin, end, it);
}

template <typename OutChar, typename InputIt, typename OutputIt,
          FMT_ENABLE_IF(needs_conversion<InputIt, OutChar>::value)>
OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
  return std::transform(begin, end, it, to_char8_t);
}

#ifndef FMT_USE_GRISU
#  define FMT_USE_GRISU 1
#endif

template <typename T> constexpr bool use_grisu() {
  return FMT_USE_GRISU && std::numeric_limits<double>::is_iec559 &&
         sizeof(T) <= sizeof(double);
}

template <typename T>
template <typename U>
void buffer<T>::append(const U* begin, const U* end) {
  std::size_t new_size = size_ + to_unsigned(end - begin);
  reserve(new_size);
  std::uninitialized_copy(begin, end, make_checked(ptr_, capacity_) + size_);
  size_ = new_size;
}
}  // namespace internal

// A range with an iterator appending to a buffer.
template <typename T>
class buffer_range : public internal::output_range<
                         std::back_insert_iterator<internal::buffer<T>>, T> {
 public:
  using iterator = std::back_insert_iterator<internal::buffer<T>>;
  using internal::output_range<iterator, T>::output_range;
  buffer_range(internal::buffer<T>& buf)
      : internal::output_range<iterator, T>(std::back_inserter(buf)) {}
};

// A UTF-8 string view.
class u8string_view : public basic_string_view<char8_t> {
 public:
  u8string_view(const char* s)
      : basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s)) {}
  u8string_view(const char* s, size_t count) FMT_NOEXCEPT
      : basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s), count) {
  }
};

#if FMT_USE_USER_DEFINED_LITERALS
inline namespace literals {
inline u8string_view operator"" _u(const char* s, std::size_t n) {
  return {s, n};
}
}  // namespace literals
#endif

// The number of characters to store in the basic_memory_buffer object itself
// to avoid dynamic memory allocation.
enum { inline_buffer_size = 500 };

/**
  \rst
  A dynamically growing memory buffer for trivially copyable/constructible types
  with the first ``SIZE`` elements stored in the object itself.

  You can use one of the following type aliases for common character types:

  +----------------+------------------------------+
  | Type           | Definition                   |
  +================+==============================+
  | memory_buffer  | basic_memory_buffer<char>    |
  +----------------+------------------------------+
  | wmemory_buffer | basic_memory_buffer<wchar_t> |
  +----------------+------------------------------+

  **Example**::

     fmt::memory_buffer out;
     format_to(out, "The answer is {}.", 42);

  This will append the following output to the ``out`` object:

  .. code-block:: none

     The answer is 42.

  The output can be converted to an ``std::string`` with ``to_string(out)``.
  \endrst
 */
template <typename T, std::size_t SIZE = inline_buffer_size,
          typename Allocator = std::allocator<T>>
class basic_memory_buffer : private Allocator, public internal::buffer<T> {
 private:
  T store_[SIZE];

  // Deallocate memory allocated by the buffer.
  void deallocate() {
    T* data = this->data();
    if (data != store_) Allocator::deallocate(data, this->capacity());
  }

 protected:
  void grow(std::size_t size) FMT_OVERRIDE;

 public:
  using value_type = T;
  using const_reference = const T&;

  explicit basic_memory_buffer(const Allocator& alloc = Allocator())
      : Allocator(alloc) {
    this->set(store_, SIZE);
  }
  ~basic_memory_buffer() FMT_OVERRIDE { deallocate(); }

 private:
  // Move data from other to this buffer.
  void move(basic_memory_buffer& other) {
    Allocator &this_alloc = *this, &other_alloc = other;
    this_alloc = std::move(other_alloc);
    T* data = other.data();
    std::size_t size = other.size(), capacity = other.capacity();
    if (data == other.store_) {
      this->set(store_, capacity);
      std::uninitialized_copy(other.store_, other.store_ + size,
                              internal::make_checked(store_, capacity));
    } else {
      this->set(data, capacity);
      // Set pointer to the inline array so that delete is not called
      // when deallocating.
      other.set(other.store_, 0);
    }
    this->resize(size);
  }

 public:
  /**
    \rst
    Constructs a :class:`fmt::basic_memory_buffer` object moving the content
    of the other object to it.
    \endrst
   */
  basic_memory_buffer(basic_memory_buffer&& other) FMT_NOEXCEPT { move(other); }

  /**
    \rst
    Moves the content of the other ``basic_memory_buffer`` object to this one.
    \endrst
   */
  basic_memory_buffer& operator=(basic_memory_buffer&& other) FMT_NOEXCEPT {
    FMT_ASSERT(this != &other, "");
    deallocate();
    move(other);
    return *this;
  }

  // Returns a copy of the allocator associated with this buffer.
  Allocator get_allocator() const { return *this; }
};

template <typename T, std::size_t SIZE, typename Allocator>
void basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) {
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  if (size > 1000) throw std::runtime_error("fuzz mode - won't grow that much");
#endif
  std::size_t old_capacity = this->capacity();
  std::size_t new_capacity = old_capacity + old_capacity / 2;
  if (size > new_capacity) new_capacity = size;
  T* old_data = this->data();
  T* new_data = std::allocator_traits<Allocator>::allocate(*this, new_capacity);
  // The following code doesn't throw, so the raw pointer above doesn't leak.
  std::uninitialized_copy(old_data, old_data + this->size(),
                          internal::make_checked(new_data, new_capacity));
  this->set(new_data, new_capacity);
  // deallocate must not throw according to the standard, but even if it does,
  // the buffer already uses the new storage and will deallocate it in
  // destructor.
  if (old_data != store_) Allocator::deallocate(old_data, old_capacity);
}

using memory_buffer = basic_memory_buffer<char>;
using wmemory_buffer = basic_memory_buffer<wchar_t>;

namespace internal {

// Returns true if value is negative, false otherwise.
// Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
template <typename T, FMT_ENABLE_IF(std::numeric_limits<T>::is_signed)>
FMT_CONSTEXPR bool is_negative(T value) {
  return value < 0;
}
template <typename T, FMT_ENABLE_IF(!std::numeric_limits<T>::is_signed)>
FMT_CONSTEXPR bool is_negative(T) {
  return false;
}

// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
// represent all values of T.
template <typename T>
using uint32_or_64_or_128_t = conditional_t<
    std::numeric_limits<T>::digits <= 32, uint32_t,
    conditional_t<std::numeric_limits<T>::digits <= 64, uint64_t, uint128_t>>;

// Static data is placed in this class template for the header-only config.
template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
  static const uint64_t powers_of_10_64[];
  static const uint32_t zero_or_powers_of_10_32[];
  static const uint64_t zero_or_powers_of_10_64[];
  static const uint64_t pow10_significands[];
  static const int16_t pow10_exponents[];
  static const char digits[];
  static const char hex_digits[];
  static const char foreground_color[];
  static const char background_color[];
  static const char reset_color[5];
  static const wchar_t wreset_color[5];
  static const char signs[];
};

FMT_EXTERN template struct basic_data<void>;

// This is a struct rather than an alias to avoid shadowing warnings in gcc.
struct data : basic_data<> {};

#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
inline int count_digits(uint64_t n) {
  // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
  // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
  int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
  return t - (n < data::zero_or_powers_of_10_64[t]) + 1;
}
#else
// Fallback version of count_digits used when __builtin_clz is not available.
inline int count_digits(uint64_t n) {
  int count = 1;
  for (;;) {
    // Integer division is slow so do it for a group of four digits instead
    // of for every digit. The idea comes from the talk by Alexandrescu
    // "Three Optimization Tips for C++". See speed-test for a comparison.
    if (n < 10) return count;
    if (n < 100) return count + 1;
    if (n < 1000) return count + 2;
    if (n < 10000) return count + 3;
    n /= 10000u;
    count += 4;
  }
}
#endif

#if FMT_USE_INT128
inline int count_digits(uint128_t n) {
  int count = 1;
  for (;;) {
    // Integer division is slow so do it for a group of four digits instead
    // of for every digit. The idea comes from the talk by Alexandrescu
    // "Three Optimization Tips for C++". See speed-test for a comparison.
    if (n < 10) return count;
    if (n < 100) return count + 1;
    if (n < 1000) return count + 2;
    if (n < 10000) return count + 3;
    n /= 10000U;
    count += 4;
  }
}
#endif

// Counts the number of digits in n. BITS = log2(radix).
template <unsigned BITS, typename UInt> inline int count_digits(UInt n) {
  int num_digits = 0;
  do {
    ++num_digits;
  } while ((n >>= BITS) != 0);
  return num_digits;
}

template <> int count_digits<4>(internal::fallback_uintptr n);

#if FMT_GCC_VERSION || FMT_CLANG_VERSION
#  define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
#else
#  define FMT_ALWAYS_INLINE
#endif

#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
inline int count_digits(uint32_t n) {
  int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
  return t - (n < data::zero_or_powers_of_10_32[t]) + 1;
}
#endif

template <typename Char> FMT_API std::string grouping_impl(locale_ref loc);
template <typename Char> inline std::string grouping(locale_ref loc) {
  return grouping_impl<char>(loc);
}
template <> inline std::string grouping<wchar_t>(locale_ref loc) {
  return grouping_impl<wchar_t>(loc);
}

template <typename Char> FMT_API Char thousands_sep_impl(locale_ref loc);
template <typename Char> inline Char thousands_sep(locale_ref loc) {
  return Char(thousands_sep_impl<char>(loc));
}
template <> inline wchar_t thousands_sep(locale_ref loc) {
  return thousands_sep_impl<wchar_t>(loc);
}

template <typename Char> FMT_API Char decimal_point_impl(locale_ref loc);
template <typename Char> inline Char decimal_point(locale_ref loc) {
  return Char(decimal_point_impl<char>(loc));
}
template <> inline wchar_t decimal_point(locale_ref loc) {
  return decimal_point_impl<wchar_t>(loc);
}

// Formats a decimal unsigned integer value writing into buffer.
// add_thousands_sep is called after writing each char to add a thousands
// separator if necessary.
template <typename UInt, typename Char, typename F>
inline Char* format_decimal(Char* buffer, UInt value, int num_digits,
                            F add_thousands_sep) {
  FMT_ASSERT(num_digits >= 0, "invalid digit count");
  buffer += num_digits;
  Char* end = buffer;
  while (value >= 100) {
    // Integer division is slow so do it for a group of two digits instead
    // of for every digit. The idea comes from the talk by Alexandrescu
    // "Three Optimization Tips for C++". See speed-test for a comparison.
    auto index = static_cast<unsigned>((value % 100) * 2);
    value /= 100;
    *--buffer = static_cast<Char>(data::digits[index + 1]);
    add_thousands_sep(buffer);
    *--buffer = static_cast<Char>(data::digits[index]);
    add_thousands_sep(buffer);
  }
  if (value < 10) {
    *--buffer = static_cast<Char>('0' + value);
    return end;
  }
  auto index = static_cast<unsigned>(value * 2);
  *--buffer = static_cast<Char>(data::digits[index + 1]);
  add_thousands_sep(buffer);
  *--buffer = static_cast<Char>(data::digits[index]);
  return end;
}

template <typename Int> constexpr int digits10() noexcept {
  return std::numeric_limits<Int>::digits10;
}
template <> constexpr int digits10<int128_t>() noexcept { return 38; }
template <> constexpr int digits10<uint128_t>() noexcept { return 38; }

template <typename Char, typename UInt, typename Iterator, typename F>
inline Iterator format_decimal(Iterator out, UInt value, int num_digits,
                               F add_thousands_sep) {
  FMT_ASSERT(num_digits >= 0, "invalid digit count");
  // Buffer should be large enough to hold all digits (<= digits10 + 1).
  enum { max_size = digits10<UInt>() + 1 };
  Char buffer[2 * max_size];
  auto end = format_decimal(buffer, value, num_digits, add_thousands_sep);
  return internal::copy_str<Char>(buffer, end, out);
}

template <typename Char, typename It, typename UInt>
inline It format_decimal(It out, UInt value, int num_digits) {
  return format_decimal<Char>(out, value, num_digits, [](Char*) {});
}

template <unsigned BASE_BITS, typename Char, typename UInt>
inline Char* format_uint(Char* buffer, UInt value, int num_digits,
                         bool upper = false) {
  buffer += num_digits;
  Char* end = buffer;
  do {
    const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits;
    unsigned digit = (value & ((1 << BASE_BITS) - 1));
    *--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit)
                                                : digits[digit]);
  } while ((value >>= BASE_BITS) != 0);
  return end;
}

template <unsigned BASE_BITS, typename Char>
Char* format_uint(Char* buffer, internal::fallback_uintptr n, int num_digits,
                  bool = false) {
  auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
  int start = (num_digits + char_digits - 1) / char_digits - 1;
  if (int start_digits = num_digits % char_digits) {
    unsigned value = n.value[start--];
    buffer = format_uint<BASE_BITS>(buffer, value, start_digits);
  }
  for (; start >= 0; --start) {
    unsigned value = n.value[start];
    buffer += char_digits;
    auto p = buffer;
    for (int i = 0; i < char_digits; ++i) {
      unsigned digit = (value & ((1 << BASE_BITS) - 1));
      *--p = static_cast<Char>(data::hex_digits[digit]);
      value >>= BASE_BITS;
    }
  }
  return buffer;
}

template <unsigned BASE_BITS, typename Char, typename It, typename UInt>
inline It format_uint(It out, UInt value, int num_digits, bool upper = false) {
  // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1).
  char buffer[num_bits<UInt>() / BASE_BITS + 1];
  format_uint<BASE_BITS>(buffer, value, num_digits, upper);
  return internal::copy_str<Char>(buffer, buffer + num_digits, out);
}

template <typename T = void> struct null {};

// Workaround an array initialization issue in gcc 4.8.
template <typename Char> struct fill_t {
 private:
  Char data_[6];

 public:
  FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; }
  FMT_CONSTEXPR const Char& operator[](size_t index) const {
    return data_[index];
  }

  static FMT_CONSTEXPR fill_t<Char> make() {
    auto fill = fill_t<Char>();
    fill[0] = Char(' ');
    return fill;
  }
};
}  // namespace internal

// We cannot use enum classes as bit fields because of a gcc bug
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414.
namespace align {
enum type { none, left, right, center, numeric };
}
using align_t = align::type;

namespace sign {
enum type { none, minus, plus, space };
}
using sign_t = sign::type;

// Format specifiers for built-in and string types.
template <typename Char> struct basic_format_specs {
  int width;
  int precision;
  char type;
  align_t align : 4;
  sign_t sign : 3;
  bool alt : 1;  // Alternate form ('#').
  internal::fill_t<Char> fill;

  constexpr basic_format_specs()
      : width(0),
        precision(-1),
        type(0),
        align(align::none),
        sign(sign::none),
        alt(false),
        fill(internal::fill_t<Char>::make()) {}
};

using format_specs = basic_format_specs<char>;

namespace internal {

// A floating-point presentation format.
enum class float_format : unsigned char {
  general,  // General: exponent notation or fixed point based on magnitude.
  exp,      // Exponent notation with the default precision of 6, e.g. 1.2e-3.
  fixed,    // Fixed point with the default precision of 6, e.g. 0.0012.
  hex
};

struct float_specs {
  int precision;
  float_format format : 8;
  sign_t sign : 8;
  bool upper : 1;
  bool locale : 1;
  bool percent : 1;
  bool binary32 : 1;
  bool use_grisu : 1;
  bool trailing_zeros : 1;
};

// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
template <typename Char, typename It> It write_exponent(int exp, It it) {
  FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range");
  if (exp < 0) {
    *it++ = static_cast<Char>('-');
    exp = -exp;
  } else {
    *it++ = static_cast<Char>('+');
  }
  if (exp >= 100) {
    const char* top = data::digits + (exp / 100) * 2;
    if (exp >= 1000) *it++ = static_cast<Char>(top[0]);
    *it++ = static_cast<Char>(top[1]);
    exp %= 100;
  }
  const char* d = data::digits + exp * 2;
  *it++ = static_cast<Char>(d[0]);
  *it++ = static_cast<Char>(d[1]);
  return it;
}

template <typename Char> class float_writer {
 private:
  // The number is given as v = digits_ * pow(10, exp_).
  const char* digits_;
  int num_digits_;
  int exp_;
  size_t size_;
  float_specs specs_;
  Char decimal_point_;

  template <typename It> It prettify(It it) const {
    // pow(10, full_exp - 1) <= v <= pow(10, full_exp).
    int full_exp = num_digits_ + exp_;
    if (specs_.format == float_format::exp) {
      // Insert a decimal point after the first digit and add an exponent.
      *it++ = static_cast<Char>(*digits_);
      int num_zeros = specs_.precision - num_digits_;
      bool trailing_zeros = num_zeros > 0 && specs_.trailing_zeros;
      if (num_digits_ > 1 || trailing_zeros) *it++ = decimal_point_;
      it = copy_str<Char>(digits_ + 1, digits_ + num_digits_, it);
      if (trailing_zeros)
        it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
      *it++ = static_cast<Char>(specs_.upper ? 'E' : 'e');
      return write_exponent<Char>(full_exp - 1, it);
    }
    if (num_digits_ <= full_exp) {
      // 1234e7 -> 12340000000[.0+]
      it = copy_str<Char>(digits_, digits_ + num_digits_, it);
      it = std::fill_n(it, full_exp - num_digits_, static_cast<Char>('0'));
      if (specs_.trailing_zeros) {
        *it++ = decimal_point_;
        int num_zeros = specs_.precision - full_exp;
        if (num_zeros <= 0) {
          if (specs_.format != float_format::fixed)
            *it++ = static_cast<Char>('0');
          return it;
        }
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
        if (num_zeros > 1000)
          throw std::runtime_error("fuzz mode - avoiding excessive cpu use");
#endif
        it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
      }
    } else if (full_exp > 0) {
      // 1234e-2 -> 12.34[0+]
      it = copy_str<Char>(digits_, digits_ + full_exp, it);
      if (!specs_.trailing_zeros) {
        // Remove trailing zeros.
        int num_digits = num_digits_;
        while (num_digits > full_exp && digits_[num_digits - 1] == '0')
          --num_digits;
        if (num_digits != full_exp) *it++ = decimal_point_;
        return copy_str<Char>(digits_ + full_exp, digits_ + num_digits, it);
      }
      *it++ = decimal_point_;
      it = copy_str<Char>(digits_ + full_exp, digits_ + num_digits_, it);
      if (specs_.precision > num_digits_) {
        // Add trailing zeros.
        int num_zeros = specs_.precision - num_digits_;
        it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
      }
    } else {
      // 1234e-6 -> 0.001234
      *it++ = static_cast<Char>('0');
      int num_zeros = -full_exp;
      if (specs_.precision >= 0 && specs_.precision < num_zeros)
        num_zeros = specs_.precision;
      int num_digits = num_digits_;
      if (!specs_.trailing_zeros)
        while (num_digits > 0 && digits_[num_digits - 1] == '0') --num_digits;
      if (num_zeros != 0 || num_digits != 0) {
        *it++ = decimal_point_;
        it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
        it = copy_str<Char>(digits_, digits_ + num_digits, it);
      }
    }
    return it;
  }

 public:
  float_writer(const char* digits, int num_digits, int exp, float_specs specs,
               Char decimal_point)
      : digits_(digits),
        num_digits_(num_digits),
        exp_(exp),
        specs_(specs),
        decimal_point_(decimal_point) {
    int full_exp = num_digits + exp - 1;
    int precision = specs.precision > 0 ? specs.precision : 16;
    if (specs_.format == float_format::general &&
        !(full_exp >= -4 && full_exp < precision)) {
      specs_.format = float_format::exp;
    }
    size_ = prettify(counting_iterator()).count();
    size_ += specs.sign ? 1 : 0;
  }

  size_t size() const { return size_; }
  size_t width() const { return size(); }

  template <typename It> void operator()(It&& it) {
    if (specs_.sign) *it++ = static_cast<Char>(data::signs[specs_.sign]);
    it = prettify(it);
  }
};

template <typename T>
int format_float(T value, int precision, float_specs specs, buffer<char>& buf);

// Formats a floating-point number with snprintf.
template <typename T>
int snprintf_float(T value, int precision, float_specs specs,
                   buffer<char>& buf);

template <typename T> T promote_float(T value) { return value; }
inline double promote_float(float value) { return value; }

template <typename Handler>
FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
  switch (spec) {
  case 0:
  case 'd':
    handler.on_dec();
    break;
  case 'x':
  case 'X':
    handler.on_hex();
    break;
  case 'b':
  case 'B':
    handler.on_bin();
    break;
  case 'o':
    handler.on_oct();
    break;
  case 'n':
    handler.on_num();
    break;
  default:
    handler.on_error();
  }
}

template <typename ErrorHandler = error_handler, typename Char>
FMT_CONSTEXPR float_specs parse_float_type_spec(
    const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
  auto result = float_specs();
  result.trailing_zeros = specs.alt;
  switch (specs.type) {
  case 0:
    result.format = float_format::general;
    result.trailing_zeros |= specs.precision != 0;
    break;
  case 'G':
    result.upper = true;
    FMT_FALLTHROUGH;
  case 'g':
    result.format = float_format::general;
    break;
  case 'E':
    result.upper = true;
    FMT_FALLTHROUGH;
  case 'e':
    result.format = float_format::exp;
    result.trailing_zeros |= specs.precision != 0;
    break;
  case 'F':
    result.upper = true;
    FMT_FALLTHROUGH;
  case 'f':
    result.format = float_format::fixed;
    result.trailing_zeros |= specs.precision != 0;
    break;
#if FMT_DEPRECATED_PERCENT
  case '%':
    result.format = float_format::fixed;
    result.percent = true;
    break;
#endif
  case 'A':
    result.upper = true;
    FMT_FALLTHROUGH;
  case 'a':
    result.format = float_format::hex;
    break;
  case 'n':
    result.locale = true;
    break;
  default:
    eh.on_error("invalid type specifier");
    break;
  }
  return result;
}

template <typename Char, typename Handler>
FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char>* specs,
                                     Handler&& handler) {
  if (!specs) return handler.on_char();
  if (specs->type && specs->type != 'c') return handler.on_int();
  if (specs->align == align::numeric || specs->sign != sign::none || specs->alt)
    handler.on_error("invalid format specifier for char");
  handler.on_char();
}

template <typename Char, typename Handler>
FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) {
  if (spec == 0 || spec == 's')
    handler.on_string();
  else if (spec == 'p')
    handler.on_pointer();
  else
    handler.on_error("invalid type specifier");
}

template <typename Char, typename ErrorHandler>
FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) {
  if (spec != 0 && spec != 's') eh.on_error("invalid type specifier");
}

template <typename Char, typename ErrorHandler>
FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
  if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
}

template <typename ErrorHandler> class int_type_checker : private ErrorHandler {
 public:
  FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {}

  FMT_CONSTEXPR void on_dec() {}
  FMT_CONSTEXPR void on_hex() {}
  FMT_CONSTEXPR void on_bin() {}
  FMT_CONSTEXPR void on_oct() {}
  FMT_CONSTEXPR void on_num() {}

  FMT_CONSTEXPR void on_error() {
    ErrorHandler::on_error("invalid type specifier");
  }
};

template <typename ErrorHandler>
class char_specs_checker : public ErrorHandler {
 private:
  char type_;

 public:
  FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh)
      : ErrorHandler(eh), type_(type) {}

  FMT_CONSTEXPR void on_int() {
    handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this));
  }
  FMT_CONSTEXPR void on_char() {}
};

template <typename ErrorHandler>
class cstring_type_checker : public ErrorHandler {
 public:
  FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh)
      : ErrorHandler(eh) {}

  FMT_CONSTEXPR void on_string() {}
  FMT_CONSTEXPR void on_pointer() {}
};

template <typename Context>
void arg_map<Context>::init(const basic_format_args<Context>& args) {
  if (map_) return;
  map_ = new entry[internal::to_unsigned(args.max_size())];
  if (args.is_packed()) {
    for (int i = 0;; ++i) {
      internal::type arg_type = args.type(i);
      if (arg_type == internal::none_type) return;
      if (arg_type == internal::named_arg_type) push_back(args.values_[i]);
    }
  }
  for (int i = 0, n = args.max_size(); i < n; ++i) {
    auto type = args.args_[i].type_;
    if (type == internal::named_arg_type) push_back(args.args_[i].value_);
  }
}

template <typename Char> struct nonfinite_writer {
  sign_t sign;
  const char* str;
  static constexpr size_t str_size = 3;

  size_t size() const { return str_size + (sign ? 1 : 0); }
  size_t width() const { return size(); }

  template <typename It> void operator()(It&& it) const {
    if (sign) *it++ = static_cast<Char>(data::signs[sign]);
    it = copy_str<Char>(str, str + str_size, it);
  }
};

// This template provides operations for formatting and writing data into a
// character range.
template <typename Range> class basic_writer {
 public:
  using char_type = typename Range::value_type;
  using iterator = typename Range::iterator;
  using format_specs = basic_format_specs<char_type>;

 private:
  iterator out_;  // Output iterator.
  locale_ref locale_;

  // Attempts to reserve space for n extra characters in the output range.
  // Returns a pointer to the reserved range or a reference to out_.
  auto reserve(std::size_t n) -> decltype(internal::reserve(out_, n)) {
    return internal::reserve(out_, n);
  }

  template <typename F> struct padded_int_writer {
    size_t size_;
    string_view prefix;
    char_type fill;
    std::size_t padding;
    F f;

    size_t size() const { return size_; }
    size_t width() const { return size_; }

    template <typename It> void operator()(It&& it) const {
      if (prefix.size() != 0)
        it = copy_str<char_type>(prefix.begin(), prefix.end(), it);
      it = std::fill_n(it, padding, fill);
      f(it);
    }
  };

  // Writes an integer in the format
  //   <left-padding><prefix><numeric-padding><digits><right-padding>
  // where <digits> are written by f(it).
  template <typename F>
  void write_int(int num_digits, string_view prefix, format_specs specs, F f) {
    std::size_t size = prefix.size() + to_unsigned(num_digits);
    char_type fill = specs.fill[0];
    std::size_t padding = 0;
    if (specs.align == align::numeric) {
      auto unsiged_width = to_unsigned(specs.width);
      if (unsiged_width > size) {
        padding = unsiged_width - size;
        size = unsiged_width;
      }
    } else if (specs.precision > num_digits) {
      size = prefix.size() + to_unsigned(specs.precision);
      padding = to_unsigned(specs.precision - num_digits);
      fill = static_cast<char_type>('0');
    }
    if (specs.align == align::none) specs.align = align::right;
    write_padded(specs, padded_int_writer<F>{size, prefix, fill, padding, f});
  }

  // Writes a decimal integer.
  template <typename Int> void write_decimal(Int value) {
    auto abs_value = static_cast<uint32_or_64_or_128_t<Int>>(value);
    bool negative = is_negative(value);
    // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer.
    if (negative) abs_value = ~abs_value + 1;
    int num_digits = count_digits(abs_value);
    auto&& it = reserve((negative ? 1 : 0) + static_cast<size_t>(num_digits));
    if (negative) *it++ = static_cast<char_type>('-');
    it = format_decimal<char_type>(it, abs_value, num_digits);
  }

  // The handle_int_type_spec handler that writes an integer.
  template <typename Int, typename Specs> struct int_writer {
    using unsigned_type = uint32_or_64_or_128_t<Int>;

    basic_writer<Range>& writer;
    const Specs& specs;
    unsigned_type abs_value;
    char prefix[4];
    unsigned prefix_size;

    string_view get_prefix() const { return string_view(prefix, prefix_size); }

    int_writer(basic_writer<Range>& w, Int value, const Specs& s)
        : writer(w),
          specs(s),
          abs_value(static_cast<unsigned_type>(value)),
          prefix_size(0) {
      if (is_negative(value)) {
        prefix[0] = '-';
        ++prefix_size;
        abs_value = 0 - abs_value;
      } else if (specs.sign != sign::none && specs.sign != sign::minus) {
        prefix[0] = specs.sign == sign::plus ? '+' : ' ';
        ++prefix_size;
      }
    }

    struct dec_writer {
      unsigned_type abs_value;
      int num_digits;

      template <typename It> void operator()(It&& it) const {
        it = internal::format_decimal<char_type>(it, abs_value, num_digits);
      }
    };

    void on_dec() {
      int num_digits = count_digits(abs_value);
      writer.write_int(num_digits, get_prefix(), specs,
                       dec_writer{abs_value, num_digits});
    }

    struct hex_writer {
      int_writer& self;
      int num_digits;

      template <typename It> void operator()(It&& it) const {
        it = format_uint<4, char_type>(it, self.abs_value, num_digits,
                                       self.specs.type != 'x');
      }
    };

    void on_hex() {
      if (specs.alt) {
        prefix[prefix_size++] = '0';
        prefix[prefix_size++] = specs.type;
      }
      int num_digits = count_digits<4>(abs_value);
      writer.write_int(num_digits, get_prefix(), specs,
                       hex_writer{*this, num_digits});
    }

    template <int BITS> struct bin_writer {
      unsigned_type abs_value;
      int num_digits;

      template <typename It> void operator()(It&& it) const {
        it = format_uint<BITS, char_type>(it, abs_value, num_digits);
      }
    };

    void on_bin() {
      if (specs.alt) {
        prefix[prefix_size++] = '0';
        prefix[prefix_size++] = static_cast<char>(specs.type);
      }
      int num_digits = count_digits<1>(abs_value);
      writer.write_int(num_digits, get_prefix(), specs,
                       bin_writer<1>{abs_value, num_digits});
    }

    void on_oct() {
      int num_digits = count_digits<3>(abs_value);
      if (specs.alt && specs.precision <= num_digits && abs_value != 0) {
        // Octal prefix '0' is counted as a digit, so only add it if precision
        // is not greater than the number of digits.
        prefix[prefix_size++] = '0';
      }
      writer.write_int(num_digits, get_prefix(), specs,
                       bin_writer<3>{abs_value, num_digits});
    }

    enum { sep_size = 1 };

    struct num_writer {
      unsigned_type abs_value;
      int size;
      const std::string& groups;
      char_type sep;

      template <typename It> void operator()(It&& it) const {
        basic_string_view<char_type> s(&sep, sep_size);
        // Index of a decimal digit with the least significant digit having
        // index 0.
        int digit_index = 0;
        std::string::const_iterator group = groups.cbegin();
        it = format_decimal<char_type>(
            it, abs_value, size,
            [this, s, &group, &digit_index](char_type*& buffer) {
              if (*group <= 0 || ++digit_index % *group != 0 ||
                  *group == max_value<char>())
                return;
              if (group + 1 != groups.cend()) {
                digit_index = 0;
                ++group;
              }
              buffer -= s.size();
              std::uninitialized_copy(s.data(), s.data() + s.size(),
                                      make_checked(buffer, s.size()));
            });
      }
    };

    void on_num() {
      std::string groups = grouping<char_type>(writer.locale_);
      if (groups.empty()) return on_dec();
      auto sep = thousands_sep<char_type>(writer.locale_);
      if (!sep) return on_dec();
      int num_digits = count_digits(abs_value);
      int size = num_digits;
      std::string::const_iterator group = groups.cbegin();
      while (group != groups.cend() && num_digits > *group && *group > 0 &&
             *group != max_value<char>()) {
        size += sep_size;
        num_digits -= *group;
        ++group;
      }
      if (group == groups.cend())
        size += sep_size * ((num_digits - 1) / groups.back());
      writer.write_int(size, get_prefix(), specs,
                       num_writer{abs_value, size, groups, sep});
    }

    FMT_NORETURN void on_error() {
      FMT_THROW(duckdb::Exception("invalid type specifier"));
    }
  };

  template <typename Char> struct str_writer {
    const Char* s;
    size_t size_;

    size_t size() const { return size_; }
    size_t width() const {
      return count_code_points(basic_string_view<Char>(s, size_));
    }

    template <typename It> void operator()(It&& it) const {
      it = copy_str<char_type>(s, s + size_, it);
    }
  };

  template <typename UIntPtr> struct pointer_writer {
    UIntPtr value;
    int num_digits;

    size_t size() const { return to_unsigned(num_digits) + 2; }
    size_t width() const { return size(); }

    template <typename It> void operator()(It&& it) const {
      *it++ = static_cast<char_type>('0');
      *it++ = static_cast<char_type>('x');
      it = format_uint<4, char_type>(it, value, num_digits);
    }
  };

 public:
  explicit basic_writer(Range out, locale_ref loc = locale_ref())
      : out_(out.begin()), locale_(loc) {}

  iterator out() const { return out_; }

  // Writes a value in the format
  //   <left-padding><value><right-padding>
  // where <value> is written by f(it).
  template <typename F> void write_padded(const format_specs& specs, F&& f) {
    // User-perceived width (in code points).
    unsigned width = to_unsigned(specs.width);
    size_t size = f.size();  // The number of code units.
    size_t num_code_points = width != 0 ? f.width() : size;
    if (width <= num_code_points) return f(reserve(size));
    auto&& it = reserve(width + (size - num_code_points));
    char_type fill = specs.fill[0];
    std::size_t padding = width - num_code_points;
    if (specs.align == align::right) {
      it = std::fill_n(it, padding, fill);
      f(it);
    } else if (specs.align == align::center) {
      std::size_t left_padding = padding / 2;
      it = std::fill_n(it, left_padding, fill);
      f(it);
      it = std::fill_n(it, padding - left_padding, fill);
    } else {
      f(it);
      it = std::fill_n(it, padding, fill);
    }
  }

  void write(int value) { write_decimal(value); }
  void write(long value) { write_decimal(value); }
  void write(long long value) { write_decimal(value); }

  void write(unsigned value) { write_decimal(value); }
  void write(unsigned long value) { write_decimal(value); }
  void write(unsigned long long value) { write_decimal(value); }

#if FMT_USE_INT128
  void write(int128_t value) { write_decimal(value); }
  void write(uint128_t value) { write_decimal(value); }
#endif

  template <typename T, typename Spec>
  void write_int(T value, const Spec& spec) {
    handle_int_type_spec(spec.type, int_writer<T, Spec>(*this, value, spec));
  }

  template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
  void write(T value, format_specs specs = {}) {
    float_specs fspecs = parse_float_type_spec(specs);
    fspecs.sign = specs.sign;
    if (std::signbit(value)) {  // value < 0 is false for NaN so use signbit.
      fspecs.sign = sign::minus;
      value = -value;
    } else if (fspecs.sign == sign::minus) {
      fspecs.sign = sign::none;
    }

    if (!std::isfinite(value)) {
      auto str = std::isinf(value) ? (fspecs.upper ? "INF" : "inf")
                                   : (fspecs.upper ? "NAN" : "nan");
      return write_padded(specs, nonfinite_writer<char_type>{fspecs.sign, str});
    }

    if (specs.align == align::none) {
      specs.align = align::right;
    } else if (specs.align == align::numeric) {
      if (fspecs.sign) {
        auto&& it = reserve(1);
        *it++ = static_cast<char_type>(data::signs[fspecs.sign]);
        fspecs.sign = sign::none;
        if (specs.width != 0) --specs.width;
      }
      specs.align = align::right;
    }

    memory_buffer buffer;
    if (fspecs.format == float_format::hex) {
      if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]);
      snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
      write_padded(specs, str_writer<char>{buffer.data(), buffer.size()});
      return;
    }
    int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
    if (fspecs.format == float_format::exp) ++precision;
    if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
    fspecs.use_grisu = use_grisu<T>();
    if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) value *= 100;
    int exp = format_float(promote_float(value), precision, fspecs, buffer);
    if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) {
      buffer.push_back('%');
      --exp;  // Adjust decimal place position.
    }
    fspecs.precision = precision;
    char_type point = fspecs.locale ? decimal_point<char_type>(locale_)
                                    : static_cast<char_type>('.');
    write_padded(specs, float_writer<char_type>(buffer.data(),
                                                static_cast<int>(buffer.size()),
                                                exp, fspecs, point));
  }

  void write(char value) {
    auto&& it = reserve(1);
    *it++ = value;
  }

  template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char_type>::value)>
  void write(Char value) {
    auto&& it = reserve(1);
    *it++ = value;
  }

  void write(string_view value) {
    auto&& it = reserve(value.size());
    it = copy_str<char_type>(value.begin(), value.end(), it);
  }
  void write(wstring_view value) {
    static_assert(std::is_same<char_type, wchar_t>::value, "");
    auto&& it = reserve(value.size());
    it = std::copy(value.begin(), value.end(), it);
  }

  template <typename Char>
  void write(const Char* s, std::size_t size, const format_specs& specs) {
    write_padded(specs, str_writer<Char>{s, size});
  }

  template <typename Char>
  void write(basic_string_view<Char> s, const format_specs& specs = {}) {
    const Char* data = s.data();
    std::size_t size = s.size();
    if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
      size = code_point_index(s, to_unsigned(specs.precision));
    write(data, size, specs);
  }

  template <typename UIntPtr>
  void write_pointer(UIntPtr value, const format_specs* specs) {
    int num_digits = count_digits<4>(value);
    auto pw = pointer_writer<UIntPtr>{value, num_digits};
    if (!specs) return pw(reserve(to_unsigned(num_digits) + 2));
    format_specs specs_copy = *specs;
    if (specs_copy.align == align::none) specs_copy.align = align::right;
    write_padded(specs_copy, pw);
  }
};

using writer = basic_writer<buffer_range<char>>;

template <typename T> struct is_integral : std::is_integral<T> {};
template <> struct is_integral<int128_t> : std::true_type {};
template <> struct is_integral<uint128_t> : std::true_type {};

template <typename Range, typename ErrorHandler = internal::error_handler>
class arg_formatter_base {
 public:
  using char_type = typename Range::value_type;
  using iterator = typename Range::iterator;
  using format_specs = basic_format_specs<char_type>;

 private:
  using writer_type = basic_writer<Range>;
  writer_type writer_;
  format_specs* specs_;

  struct char_writer {
    char_type value;

    size_t size() const { return 1; }
    size_t width() const { return 1; }

    template <typename It> void operator()(It&& it) const { *it++ = value; }
  };

  void write_char(char_type value) {
    if (specs_)
      writer_.write_padded(*specs_, char_writer{value});
    else
      writer_.write(value);
  }

  void write_pointer(const void* p) {
    writer_.write_pointer(internal::to_uintptr(p), specs_);
  }

 protected:
  writer_type& writer() { return writer_; }
  FMT_DEPRECATED format_specs* spec() { return specs_; }
  format_specs* specs() { return specs_; }
  iterator out() { return writer_.out(); }

  void write(bool value) {
    string_view sv(value ? "true" : "false");
    specs_ ? writer_.write(sv, *specs_) : writer_.write(sv);
  }

  void write(const char_type* value) {
    if (!value) {
      FMT_THROW(duckdb::Exception("string pointer is null"));
    } else {
      auto length = std::char_traits<char_type>::length(value);
      basic_string_view<char_type> sv(value, length);
      specs_ ? writer_.write(sv, *specs_) : writer_.write(sv);
    }
  }

 public:
  arg_formatter_base(Range r, format_specs* s, locale_ref loc)
      : writer_(r, loc), specs_(s) {}

  iterator operator()(monostate) {
    FMT_ASSERT(false, "invalid argument type");
    return out();
  }

  template <typename T, FMT_ENABLE_IF(is_integral<T>::value)>
  iterator operator()(T value) {
    if (specs_)
      writer_.write_int(value, *specs_);
    else
      writer_.write(value);
    return out();
  }

  iterator operator()(char_type value) {
    internal::handle_char_specs(
        specs_, char_spec_handler(*this, static_cast<char_type>(value)));
    return out();
  }

  iterator operator()(bool value) {
    if (specs_ && specs_->type) return (*this)(value ? 1 : 0);
    write(value != 0);
    return out();
  }

  template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
  iterator operator()(T value) {
    writer_.write(value, specs_ ? *specs_ : format_specs());
    return out();
  }

  struct char_spec_handler : ErrorHandler {
    arg_formatter_base& formatter;
    char_type value;

    char_spec_handler(arg_formatter_base& f, char_type val)
        : formatter(f), value(val) {}

    void on_int() {
      if (formatter.specs_)
        formatter.writer_.write_int(value, *formatter.specs_);
      else
        formatter.writer_.write(value);
    }
    void on_char() { formatter.write_char(value); }
  };

  struct cstring_spec_handler : internal::error_handler {
    arg_formatter_base& formatter;
    const char_type* value;

    cstring_spec_handler(arg_formatter_base& f, const char_type* val)
        : formatter(f), value(val) {}

    void on_string() { formatter.write(value); }
    void on_pointer() { formatter.write_pointer(value); }
  };

  iterator operator()(const char_type* value) {
    if (!specs_) return write(value), out();
    internal::handle_cstring_type_spec(specs_->type,
                                       cstring_spec_handler(*this, value));
    return out();
  }

  iterator operator()(basic_string_view<char_type> value) {
    if (specs_) {
      internal::check_string_type_spec(specs_->type, internal::error_handler());
      writer_.write(value, *specs_);
    } else {
      writer_.write(value);
    }
    return out();
  }

  iterator operator()(const void* value) {
    if (specs_)
      check_pointer_type_spec(specs_->type, internal::error_handler());
    write_pointer(value);
    return out();
  }
};

template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
  return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
}

// Parses the range [begin, end) as an unsigned integer. This function assumes
// that the range is non-empty and the first character is a digit.
template <typename Char, typename ErrorHandler>
FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end,
                                        ErrorHandler&& eh) {
  FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
  if (*begin == '0') {
    ++begin;
    return 0;
  }
  unsigned value = 0;
  // Convert to unsigned to prevent a warning.
  constexpr unsigned max_int = max_value<int>();
  unsigned big = max_int / 10;
  do {
    // Check for overflow.
    if (value > big) {
      value = max_int + 1;
      break;
    }
    value = value * 10 + unsigned(*begin - '0');
    ++begin;
  } while (begin != end && '0' <= *begin && *begin <= '9');
  if (value > max_int) eh.on_error("number is too big");
  return static_cast<int>(value);
}

template <typename Context> class custom_formatter {
 private:
  using char_type = typename Context::char_type;

  basic_format_parse_context<char_type>& parse_ctx_;
  Context& ctx_;

 public:
  explicit custom_formatter(basic_format_parse_context<char_type>& parse_ctx,
                            Context& ctx)
      : parse_ctx_(parse_ctx), ctx_(ctx) {}

  bool operator()(typename basic_format_arg<Context>::handle h) const {
    h.format(parse_ctx_, ctx_);
    return true;
  }

  template <typename T> bool operator()(T) const { return false; }
};

template <typename T>
using is_integer =
    bool_constant<is_integral<T>::value && !std::is_same<T, bool>::value &&
                  !std::is_same<T, char>::value &&
                  !std::is_same<T, wchar_t>::value>;

template <typename ErrorHandler> class width_checker {
 public:
  explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {}

  template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
  FMT_CONSTEXPR unsigned long long operator()(T value) {
    if (is_negative(value)) handler_.on_error("negative width");
    return static_cast<unsigned long long>(value);
  }

  template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
  FMT_CONSTEXPR unsigned long long operator()(T) {
    handler_.on_error("width is not integer");
    return 0;
  }

 private:
  ErrorHandler& handler_;
};

template <typename ErrorHandler> class precision_checker {
 public:
  explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {}

  template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
  FMT_CONSTEXPR unsigned long long operator()(T value) {
    if (is_negative(value)) handler_.on_error("negative precision");
    return static_cast<unsigned long long>(value);
  }

  template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
  FMT_CONSTEXPR unsigned long long operator()(T) {
    handler_.on_error("precision is not integer");
    return 0;
  }

 private:
  ErrorHandler& handler_;
};

// A format specifier handler that sets fields in basic_format_specs.
template <typename Char> class specs_setter {
 public:
  explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs)
      : specs_(specs) {}

  FMT_CONSTEXPR specs_setter(const specs_setter& other)
      : specs_(other.specs_) {}

  FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
  FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill[0] = fill; }
  FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; }
  FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; }
  FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; }
  FMT_CONSTEXPR void on_hash() { specs_.alt = true; }

  FMT_CONSTEXPR void on_zero() {
    specs_.align = align::numeric;
    specs_.fill[0] = Char('0');
  }

  FMT_CONSTEXPR void on_width(int width) { specs_.width = width; }
  FMT_CONSTEXPR void on_precision(int precision) {
    specs_.precision = precision;
  }
  FMT_CONSTEXPR void end_precision() {}

  FMT_CONSTEXPR void on_type(Char type) {
    specs_.type = static_cast<char>(type);
  }

 protected:
  basic_format_specs<Char>& specs_;
};

template <typename ErrorHandler> class numeric_specs_checker {
 public:
  FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, internal::type arg_type)
      : error_handler_(eh), arg_type_(arg_type) {}

  FMT_CONSTEXPR void require_numeric_argument() {
    if (!is_arithmetic_type(arg_type_))
      error_handler_.on_error("format specifier requires numeric argument");
  }

  FMT_CONSTEXPR void check_sign() {
    require_numeric_argument();
    if (is_integral_type(arg_type_) && arg_type_ != int_type &&
        arg_type_ != long_long_type && arg_type_ != internal::char_type) {
      error_handler_.on_error("format specifier requires signed argument");
    }
  }

  FMT_CONSTEXPR void check_precision() {
    if (is_integral_type(arg_type_) || arg_type_ == internal::pointer_type)
      error_handler_.on_error("precision not allowed for this argument type");
  }

 private:
  ErrorHandler& error_handler_;
  internal::type arg_type_;
};

// A format specifier handler that checks if specifiers are consistent with the
// argument type.
template <typename Handler> class specs_checker : public Handler {
 public:
  FMT_CONSTEXPR specs_checker(const Handler& handler, internal::type arg_type)
      : Handler(handler), checker_(*this, arg_type) {}

  FMT_CONSTEXPR specs_checker(const specs_checker& other)
      : Handler(other), checker_(*this, other.arg_type_) {}

  FMT_CONSTEXPR void on_align(align_t align) {
    if (align == align::numeric) checker_.require_numeric_argument();
    Handler::on_align(align);
  }

  FMT_CONSTEXPR void on_plus() {
    checker_.check_sign();
    Handler::on_plus();
  }

  FMT_CONSTEXPR void on_minus() {
    checker_.check_sign();
    Handler::on_minus();
  }

  FMT_CONSTEXPR void on_space() {
    checker_.check_sign();
    Handler::on_space();
  }

  FMT_CONSTEXPR void on_hash() {
    checker_.require_numeric_argument();
    Handler::on_hash();
  }

  FMT_CONSTEXPR void on_zero() {
    checker_.require_numeric_argument();
    Handler::on_zero();
  }

  FMT_CONSTEXPR void end_precision() { checker_.check_precision(); }

 private:
  numeric_specs_checker<Handler> checker_;
};

template <template <typename> class Handler, typename FormatArg,
          typename ErrorHandler>
FMT_CONSTEXPR int get_dynamic_spec(FormatArg arg, ErrorHandler eh) {
  unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg);
  if (value > to_unsigned(max_value<int>())) eh.on_error("number is too big");
  return static_cast<int>(value);
}

struct auto_id {};

template <typename Context>
FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, int id) {
  auto arg = ctx.arg(id);
  if (!arg) ctx.on_error("argument index out of range");
  return arg;
}

// The standard format specifier handler with checking.
template <typename ParseContext, typename Context>
class specs_handler : public specs_setter<typename Context::char_type> {
 public:
  using char_type = typename Context::char_type;

  FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs,
                              ParseContext& parse_ctx, Context& ctx)
      : specs_setter<char_type>(specs),
        parse_context_(parse_ctx),
        context_(ctx) {}

  template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
    this->specs_.width = get_dynamic_spec<width_checker>(
        get_arg(arg_id), context_.error_handler());
  }

  template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
    this->specs_.precision = get_dynamic_spec<precision_checker>(
        get_arg(arg_id), context_.error_handler());
  }

  void on_error(const char* message) { context_.on_error(message); }

 private:
  // This is only needed for compatibility with gcc 4.4.
  using format_arg = typename Context::format_arg;

  FMT_CONSTEXPR format_arg get_arg(auto_id) {
    return internal::get_arg(context_, parse_context_.next_arg_id());
  }

  FMT_CONSTEXPR format_arg get_arg(int arg_id) {
    parse_context_.check_arg_id(arg_id);
    return internal::get_arg(context_, arg_id);
  }

  FMT_CONSTEXPR format_arg get_arg(basic_string_view<char_type> arg_id) {
    parse_context_.check_arg_id(arg_id);
    return context_.arg(arg_id);
  }

  ParseContext& parse_context_;
  Context& context_;
};

enum class arg_id_kind { none, index, name };

// An argument reference.
template <typename Char> struct arg_ref {
  FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
  FMT_CONSTEXPR explicit arg_ref(int index)
      : kind(arg_id_kind::index), val(index) {}
  FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
      : kind(arg_id_kind::name), val(name) {}

  FMT_CONSTEXPR arg_ref& operator=(int idx) {
    kind = arg_id_kind::index;
    val.index = idx;
    return *this;
  }

  arg_id_kind kind;
  union value {
    FMT_CONSTEXPR value(int id = 0) : index{id} {}
    FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}

    int index;
    basic_string_view<Char> name;
  } val;
};

// Format specifiers with width and precision resolved at formatting rather
// than parsing time to allow re-using the same parsed specifiers with
// different sets of arguments (precompilation of format strings).
template <typename Char>
struct dynamic_format_specs : basic_format_specs<Char> {
  arg_ref<Char> width_ref;
  arg_ref<Char> precision_ref;
};

// Format spec handler that saves references to arguments representing dynamic
// width and precision to be resolved at formatting time.
template <typename ParseContext>
class dynamic_specs_handler
    : public specs_setter<typename ParseContext::char_type> {
 public:
  using char_type = typename ParseContext::char_type;

  FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs<char_type>& specs,
                                      ParseContext& ctx)
      : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}

  FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other)
      : specs_setter<char_type>(other),
        specs_(other.specs_),
        context_(other.context_) {}

  template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
    specs_.width_ref = make_arg_ref(arg_id);
  }

  template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
    specs_.precision_ref = make_arg_ref(arg_id);
  }

  FMT_CONSTEXPR void on_error(const char* message) {
    context_.on_error(message);
  }

 private:
  using arg_ref_type = arg_ref<char_type>;

  FMT_CONSTEXPR arg_ref_type make_arg_ref(int arg_id) {
    context_.check_arg_id(arg_id);
    return arg_ref_type(arg_id);
  }

  FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) {
    return arg_ref_type(context_.next_arg_id());
  }

  FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<char_type> arg_id) {
    context_.check_arg_id(arg_id);
    basic_string_view<char_type> format_str(
        context_.begin(), to_unsigned(context_.end() - context_.begin()));
    return arg_ref_type(arg_id);
  }

  dynamic_format_specs<char_type>& specs_;
  ParseContext& context_;
};

template <typename Char, typename IDHandler>
FMT_CONSTEXPR const Char* parse_arg_id(const Char* begin, const Char* end,
                                       IDHandler&& handler) {
  FMT_ASSERT(begin != end, "");
  Char c = *begin;
  if (c == '}' || c == ':') {
    handler();
    return begin;
  }
  if (c >= '0' && c <= '9') {
    int index = parse_nonnegative_int(begin, end, handler);
    if (begin == end || (*begin != '}' && *begin != ':'))
      handler.on_error("invalid format string");
    else
      handler(index);
    return begin;
  }
  if (!is_name_start(c)) {
    handler.on_error("invalid format string");
    return begin;
  }
  auto it = begin;
  do {
    ++it;
  } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9')));
  handler(basic_string_view<Char>(begin, to_unsigned(it - begin)));
  return it;
}

// Adapts SpecHandler to IDHandler API for dynamic width.
template <typename SpecHandler, typename Char> struct width_adapter {
  explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {}

  FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
  FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
  FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
    handler.on_dynamic_width(id);
  }

  FMT_CONSTEXPR void on_error(const char* message) {
    handler.on_error(message);
  }

  SpecHandler& handler;
};

// Adapts SpecHandler to IDHandler API for dynamic precision.
template <typename SpecHandler, typename Char> struct precision_adapter {
  explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {}

  FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
  FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
  FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
    handler.on_dynamic_precision(id);
  }

  FMT_CONSTEXPR void on_error(const char* message) {
    handler.on_error(message);
  }

  SpecHandler& handler;
};

// Parses fill and alignment.
template <typename Char, typename Handler>
FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
                                      Handler&& handler) {
  FMT_ASSERT(begin != end, "");
  auto align = align::none;
  int i = 0;
  if (begin + 1 != end) ++i;
  do {
    switch (static_cast<char>(begin[i])) {
    case '<':
      align = align::left;
      break;
    case '>':
      align = align::right;
      break;
#if FMT_NUMERIC_ALIGN
    case '=':
      align = align::numeric;
      break;
#endif
    case '^':
      align = align::center;
      break;
    }
    if (align != align::none) {
      if (i > 0) {
        auto c = *begin;
        if (c == '{')
          return handler.on_error("invalid fill character '{'"), begin;
        begin += 2;
        handler.on_fill(c);
      } else
        ++begin;
      handler.on_align(align);
      break;
    }
  } while (i-- > 0);
  return begin;
}

template <typename Char, typename Handler>
FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end,
                                      Handler&& handler) {
  FMT_ASSERT(begin != end, "");
  if ('0' <= *begin && *begin <= '9') {
    handler.on_width(parse_nonnegative_int(begin, end, handler));
  } else if (*begin == '{') {
    ++begin;
    if (begin != end)
      begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler));
    if (begin == end || *begin != '}')
      return handler.on_error("invalid format string"), begin;
    ++begin;
  }
  return begin;
}

template <typename Char, typename Handler>
FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
                                          Handler&& handler) {
  ++begin;
  auto c = begin != end ? *begin : Char();
  if ('0' <= c && c <= '9') {
    handler.on_precision(parse_nonnegative_int(begin, end, handler));
  } else if (c == '{') {
    ++begin;
    if (begin != end) {
      begin =
          parse_arg_id(begin, end, precision_adapter<Handler, Char>(handler));
    }
    if (begin == end || *begin++ != '}')
      return handler.on_error("invalid format string"), begin;
  } else {
    return handler.on_error("missing precision specifier"), begin;
  }
  handler.end_precision();
  return begin;
}

// Parses standard format specifiers and sends notifications about parsed
// components to handler.
template <typename Char, typename SpecHandler>
FMT_CONSTEXPR const Char* parse_format_specs(const Char* begin, const Char* end,
                                             SpecHandler&& handler) {
  if (begin == end || *begin == '}') return begin;

  begin = parse_align(begin, end, handler);
  if (begin == end) return begin;

  // Parse sign.
  switch (static_cast<char>(*begin)) {
  case '+':
    handler.on_plus();
    ++begin;
    break;
  case '-':
    handler.on_minus();
    ++begin;
    break;
  case ' ':
    handler.on_space();
    ++begin;
    break;
  }
  if (begin == end) return begin;

  if (*begin == '#') {
    handler.on_hash();
    if (++begin == end) return begin;
  }

  // Parse zero flag.
  if (*begin == '0') {
    handler.on_zero();
    if (++begin == end) return begin;
  }

  begin = parse_width(begin, end, handler);
  if (begin == end) return begin;

  // Parse precision.
  if (*begin == '.') {
    begin = parse_precision(begin, end, handler);
  }

  // Parse type.
  if (begin != end && *begin != '}') handler.on_type(*begin++);
  return begin;
}

// Return the result via the out param to workaround gcc bug 77539.
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr& out) {
  for (out = first; out != last; ++out) {
    if (*out == value) return true;
  }
  return false;
}

template <>
inline bool find<false, char>(const char* first, const char* last, char value,
                              const char*& out) {
  out = static_cast<const char*>(
      std::memchr(first, value, internal::to_unsigned(last - first)));
  return out != nullptr;
}

template <typename Handler, typename Char> struct id_adapter {
  FMT_CONSTEXPR void operator()() { handler.on_arg_id(); }
  FMT_CONSTEXPR void operator()(int id) { handler.on_arg_id(id); }
  FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
    handler.on_arg_id(id);
  }
  FMT_CONSTEXPR void on_error(const char* message) {
    handler.on_error(message);
  }
  Handler& handler;
};

template <bool IS_CONSTEXPR, typename Char, typename Handler>
FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
                                       Handler&& handler) {
  struct pfs_writer {
    FMT_CONSTEXPR void operator()(const Char* begin, const Char* end) {
      if (begin == end) return;
      for (;;) {
        const Char* p = nullptr;
        if (!find<IS_CONSTEXPR>(begin, end, '}', p))
          return handler_.on_text(begin, end);
        ++p;
        if (p == end || *p != '}')
          return handler_.on_error("unmatched '}' in format string");
        handler_.on_text(begin, p);
        begin = p + 1;
      }
    }
    Handler& handler_;
  } write{handler};
  auto begin = format_str.data();
  auto end = begin + format_str.size();
  while (begin != end) {
    // Doing two passes with memchr (one for '{' and another for '}') is up to
    // 2.5x faster than the naive one-pass implementation on big format strings.
    const Char* p = begin;
    if (*begin != '{' && !find<IS_CONSTEXPR>(begin, end, '{', p))
      return write(begin, end);
    write(begin, p);
    ++p;
    if (p == end) return handler.on_error("invalid format string");
    if (static_cast<char>(*p) == '}') {
      handler.on_arg_id();
      handler.on_replacement_field(p);
    } else if (*p == '{') {
      handler.on_text(p, p + 1);
    } else {
      p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler});
      Char c = p != end ? *p : Char();
      if (c == '}') {
        handler.on_replacement_field(p);
      } else if (c == ':') {
        p = handler.on_format_specs(p + 1, end);
        if (p == end || *p != '}')
          return handler.on_error("unknown format specifier");
      } else {
        return handler.on_error("missing '}' in format string");
      }
    }
    begin = p + 1;
  }
}

template <typename T, typename ParseContext>
FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
    ParseContext& ctx) {
  using char_type = typename ParseContext::char_type;
  using context = buffer_context<char_type>;
  using mapped_type =
      conditional_t<internal::mapped_type_constant<T, context>::value !=
                        internal::custom_type,
                    decltype(arg_mapper<context>().map(std::declval<T>())), T>;
  auto f = conditional_t<has_formatter<mapped_type, context>::value,
                         formatter<mapped_type, char_type>,
                         internal::fallback_formatter<T, char_type>>();
  return f.parse(ctx);
}

template <typename Char, typename ErrorHandler, typename... Args>
class format_string_checker {
 public:
  explicit FMT_CONSTEXPR format_string_checker(
      basic_string_view<Char> format_str, ErrorHandler eh)
      : arg_id_(-1),
        context_(format_str, eh),
        parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}

  FMT_CONSTEXPR void on_text(const Char*, const Char*) {}

  FMT_CONSTEXPR void on_arg_id() {
    arg_id_ = context_.next_arg_id();
    check_arg_id();
  }
  FMT_CONSTEXPR void on_arg_id(int id) {
    arg_id_ = id;
    context_.check_arg_id(id);
    check_arg_id();
  }
  FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) {
    on_error("compile-time checks don't support named arguments");
  }

  FMT_CONSTEXPR void on_replacement_field(const Char*) {}

  FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, const Char*) {
    advance_to(context_, begin);
    return arg_id_ < num_args ? parse_funcs_[arg_id_](context_) : begin;
  }

  FMT_CONSTEXPR void on_error(const char* message) {
    context_.on_error(message);
  }

 private:
  using parse_context_type = basic_format_parse_context<Char, ErrorHandler>;
  enum { num_args = sizeof...(Args) };

  FMT_CONSTEXPR void check_arg_id() {
    if (arg_id_ >= num_args) context_.on_error("argument index out of range");
  }

  // Format specifier parsing function.
  using parse_func = const Char* (*)(parse_context_type&);

  int arg_id_;
  parse_context_type context_;
  parse_func parse_funcs_[num_args > 0 ? num_args : 1];
};

template <typename Char, typename ErrorHandler, typename... Args>
FMT_CONSTEXPR bool do_check_format_string(basic_string_view<Char> s,
                                          ErrorHandler eh = ErrorHandler()) {
  format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
  parse_format_string<true>(s, checker);
  return true;
}

template <typename... Args, typename S,
          enable_if_t<(is_compile_string<S>::value), int>>
void check_format_string(S format_str) {
  FMT_CONSTEXPR_DECL bool invalid_format =
      internal::do_check_format_string<typename S::char_type,
                                       internal::error_handler, Args...>(
          to_string_view(format_str));
  (void)invalid_format;
}

template <template <typename> class Handler, typename Context>
void handle_dynamic_spec(int& value, arg_ref<typename Context::char_type> ref,
                         Context& ctx) {
  switch (ref.kind) {
  case arg_id_kind::none:
    break;
  case arg_id_kind::index:
    value = internal::get_dynamic_spec<Handler>(ctx.arg(ref.val.index),
                                                ctx.error_handler());
    break;
  case arg_id_kind::name:
    value = internal::get_dynamic_spec<Handler>(ctx.arg(ref.val.name),
                                                ctx.error_handler());
    break;
  }
}
}  // namespace internal

template <typename Range>
using basic_writer FMT_DEPRECATED_ALIAS = internal::basic_writer<Range>;
using writer FMT_DEPRECATED_ALIAS = internal::writer;
using wwriter FMT_DEPRECATED_ALIAS =
    internal::basic_writer<buffer_range<wchar_t>>;

/** The default argument formatter. */
template <typename Range>
class arg_formatter : public internal::arg_formatter_base<Range> {
 private:
  using char_type = typename Range::value_type;
  using base = internal::arg_formatter_base<Range>;
  using context_type = basic_format_context<typename base::iterator, char_type>;

  context_type& ctx_;
  basic_format_parse_context<char_type>* parse_ctx_;

 public:
  using range = Range;
  using iterator = typename base::iterator;
  using format_specs = typename base::format_specs;

  /**
    \rst
    Constructs an argument formatter object.
    *ctx* is a reference to the formatting context,
    *specs* contains format specifier information for standard argument types.
    \endrst
   */
  explicit arg_formatter(
      context_type& ctx,
      basic_format_parse_context<char_type>* parse_ctx = nullptr,
      format_specs* specs = nullptr)
      : base(Range(ctx.out()), specs, ctx.locale()),
        ctx_(ctx),
        parse_ctx_(parse_ctx) {}

  using base::operator();

  /** Formats an argument of a user-defined type. */
  iterator operator()(typename basic_format_arg<context_type>::handle handle) {
    handle.format(*parse_ctx_, ctx_);
    return ctx_.out();
  }
};

/** Fast integer formatter. */
class format_int {
 private:
  // Buffer should be large enough to hold all digits (digits10 + 1),
  // a sign and a null character.
  enum { buffer_size = std::numeric_limits<unsigned long long>::digits10 + 3 };
  mutable char buffer_[buffer_size];
  char* str_;

  // Formats value in reverse and returns a pointer to the beginning.
  char* format_decimal(unsigned long long value) {
    char* ptr = buffer_ + (buffer_size - 1);  // Parens to workaround MSVC bug.
    while (value >= 100) {
      // Integer division is slow so do it for a group of two digits instead
      // of for every digit. The idea comes from the talk by Alexandrescu
      // "Three Optimization Tips for C++". See speed-test for a comparison.
      auto index = static_cast<unsigned>((value % 100) * 2);
      value /= 100;
      *--ptr = internal::data::digits[index + 1];
      *--ptr = internal::data::digits[index];
    }
    if (value < 10) {
      *--ptr = static_cast<char>('0' + value);
      return ptr;
    }
    auto index = static_cast<unsigned>(value * 2);
    *--ptr = internal::data::digits[index + 1];
    *--ptr = internal::data::digits[index];
    return ptr;
  }

  void format_signed(long long value) {
    auto abs_value = static_cast<unsigned long long>(value);
    bool negative = value < 0;
    if (negative) abs_value = 0 - abs_value;
    str_ = format_decimal(abs_value);
    if (negative) *--str_ = '-';
  }

 public:
  explicit format_int(int value) { format_signed(value); }
  explicit format_int(long value) { format_signed(value); }
  explicit format_int(long long value) { format_signed(value); }
  explicit format_int(unsigned value) : str_(format_decimal(value)) {}
  explicit format_int(unsigned long value) : str_(format_decimal(value)) {}
  explicit format_int(unsigned long long value) : str_(format_decimal(value)) {}

  /** Returns the number of characters written to the output buffer. */
  std::size_t size() const {
    return internal::to_unsigned(buffer_ - str_ + buffer_size - 1);
  }

  /**
    Returns a pointer to the output buffer content. No terminating null
    character is appended.
   */
  const char* data() const { return str_; }

  /**
    Returns a pointer to the output buffer content with terminating null
    character appended.
   */
  const char* c_str() const {
    buffer_[buffer_size - 1] = '\0';
    return str_;
  }

  /**
    \rst
    Returns the content of the output buffer as an ``std::string``.
    \endrst
   */
  std::string str() const { return std::string(str_, size()); }
};

// A formatter specialization for the core types corresponding to internal::type
// constants.
template <typename T, typename Char>
struct formatter<T, Char,
                 enable_if_t<internal::type_constant<T, Char>::value !=
                             internal::custom_type>> {
  FMT_CONSTEXPR formatter() = default;

  // Parses format specifiers stopping either at the end of the range or at the
  // terminating '}'.
  template <typename ParseContext>
  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
    using handler_type = internal::dynamic_specs_handler<ParseContext>;
    auto type = internal::type_constant<T, Char>::value;
    internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
                                                  type);
    auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
    auto eh = ctx.error_handler();
    switch (type) {
    case internal::none_type:
    case internal::named_arg_type:
      FMT_ASSERT(false, "invalid argument type");
      break;
    case internal::int_type:
    case internal::uint_type:
    case internal::long_long_type:
    case internal::ulong_long_type:
    case internal::int128_type:
    case internal::uint128_type:
    case internal::bool_type:
      handle_int_type_spec(specs_.type,
                           internal::int_type_checker<decltype(eh)>(eh));
      break;
    case internal::char_type:
      handle_char_specs(
          &specs_, internal::char_specs_checker<decltype(eh)>(specs_.type, eh));
      break;
    case internal::float_type:
    case internal::double_type:
    case internal::long_double_type:
      internal::parse_float_type_spec(specs_, eh);
      break;
    case internal::cstring_type:
      internal::handle_cstring_type_spec(
          specs_.type, internal::cstring_type_checker<decltype(eh)>(eh));
      break;
    case internal::string_type:
      internal::check_string_type_spec(specs_.type, eh);
      break;
    case internal::pointer_type:
      internal::check_pointer_type_spec(specs_.type, eh);
      break;
    case internal::custom_type:
      // Custom format specifiers should be checked in parse functions of
      // formatter specializations.
      break;
    }
    return it;
  }

  template <typename FormatContext>
  auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
    internal::handle_dynamic_spec<internal::width_checker>(
        specs_.width, specs_.width_ref, ctx);
    internal::handle_dynamic_spec<internal::precision_checker>(
        specs_.precision, specs_.precision_ref, ctx);
    using range_type =
        internal::output_range<typename FormatContext::iterator,
                               typename FormatContext::char_type>;
    return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_),
                            internal::make_arg<FormatContext>(val));
  }

 private:
  internal::dynamic_format_specs<Char> specs_;
};

#define FMT_FORMAT_AS(Type, Base)                                             \
  template <typename Char>                                                    \
  struct formatter<Type, Char> : formatter<Base, Char> {                      \
    template <typename FormatContext>                                         \
    auto format(const Type& val, FormatContext& ctx) -> decltype(ctx.out()) { \
      return formatter<Base, Char>::format(val, ctx);                         \
    }                                                                         \
  }

FMT_FORMAT_AS(signed char, int);
FMT_FORMAT_AS(unsigned char, unsigned);
FMT_FORMAT_AS(short, int);
FMT_FORMAT_AS(unsigned short, unsigned);
FMT_FORMAT_AS(long, long long);
FMT_FORMAT_AS(unsigned long, unsigned long long);
FMT_FORMAT_AS(Char*, const Char*);
FMT_FORMAT_AS(std::basic_string<Char>, basic_string_view<Char>);
FMT_FORMAT_AS(std::nullptr_t, const void*);
FMT_FORMAT_AS(internal::std_string_view<Char>, basic_string_view<Char>);

template <typename Char>
struct formatter<void*, Char> : formatter<const void*, Char> {
  template <typename FormatContext>
  auto format(void* val, FormatContext& ctx) -> decltype(ctx.out()) {
    return formatter<const void*, Char>::format(val, ctx);
  }
};

template <typename Char, size_t N>
struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {
  template <typename FormatContext>
  auto format(const Char* val, FormatContext& ctx) -> decltype(ctx.out()) {
    return formatter<basic_string_view<Char>, Char>::format(val, ctx);
  }
};

// A formatter for types known only at run time such as variant alternatives.
//
// Usage:
//   using variant = std::variant<int, std::string>;
//   template <>
//   struct formatter<variant>: dynamic_formatter<> {
//     void format(buffer &buf, const variant &v, context &ctx) {
//       visit([&](const auto &val) { format(buf, val, ctx); }, v);
//     }
//   };
template <typename Char = char> class dynamic_formatter {
 private:
  struct null_handler : internal::error_handler {
    void on_align(align_t) {}
    void on_plus() {}
    void on_minus() {}
    void on_space() {}
    void on_hash() {}
  };

 public:
  template <typename ParseContext>
  auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
    format_str_ = ctx.begin();
    // Checks are deferred to formatting time when the argument type is known.
    internal::dynamic_specs_handler<ParseContext> handler(specs_, ctx);
    return parse_format_specs(ctx.begin(), ctx.end(), handler);
  }

  template <typename T, typename FormatContext>
  auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
    handle_specs(ctx);
    internal::specs_checker<null_handler> checker(
        null_handler(),
        internal::mapped_type_constant<T, FormatContext>::value);
    checker.on_align(specs_.align);
    switch (specs_.sign) {
    case sign::none:
      break;
    case sign::plus:
      checker.on_plus();
      break;
    case sign::minus:
      checker.on_minus();
      break;
    case sign::space:
      checker.on_space();
      break;
    }
    if (specs_.alt) checker.on_hash();
    if (specs_.precision >= 0) checker.end_precision();
    using range = internal::output_range<typename FormatContext::iterator,
                                         typename FormatContext::char_type>;
    visit_format_arg(arg_formatter<range>(ctx, nullptr, &specs_),
                     internal::make_arg<FormatContext>(val));
    return ctx.out();
  }

 private:
  template <typename Context> void handle_specs(Context& ctx) {
    internal::handle_dynamic_spec<internal::width_checker>(
        specs_.width, specs_.width_ref, ctx);
    internal::handle_dynamic_spec<internal::precision_checker>(
        specs_.precision, specs_.precision_ref, ctx);
  }

  internal::dynamic_format_specs<Char> specs_;
  const Char* format_str_;
};

template <typename Range, typename Char>
typename basic_format_context<Range, Char>::format_arg
basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) {
  map_.init(args_);
  format_arg arg = map_.find(name);
  if (arg.type() == internal::none_type) this->on_error("argument not found");
  return arg;
}

template <typename Char, typename ErrorHandler>
FMT_CONSTEXPR void advance_to(
    basic_format_parse_context<Char, ErrorHandler>& ctx, const Char* p) {
  ctx.advance_to(ctx.begin() + (p - &*ctx.begin()));
}

template <typename ArgFormatter, typename Char, typename Context>
struct format_handler : internal::error_handler {
  using range = typename ArgFormatter::range;

  format_handler(range r, basic_string_view<Char> str,
                 basic_format_args<Context> format_args,
                 internal::locale_ref loc)
      : parse_context(str), context(r.begin(), format_args, loc) {}

  void on_text(const Char* begin, const Char* end) {
    auto size = internal::to_unsigned(end - begin);
    auto out = context.out();
    auto&& it = internal::reserve(out, size);
    it = std::copy_n(begin, size, it);
    context.advance_to(out);
  }

  void get_arg(int id) { arg = internal::get_arg(context, id); }

  void on_arg_id() { get_arg(parse_context.next_arg_id()); }
  void on_arg_id(int id) {
    parse_context.check_arg_id(id);
    get_arg(id);
  }
  void on_arg_id(basic_string_view<Char> id) { arg = context.arg(id); }

  void on_replacement_field(const Char* p) {
    advance_to(parse_context, p);
    context.advance_to(
        visit_format_arg(ArgFormatter(context, &parse_context), arg));
  }

  const Char* on_format_specs(const Char* begin, const Char* end) {
    advance_to(parse_context, begin);
    internal::custom_formatter<Context> f(parse_context, context);
    if (visit_format_arg(f, arg)) return parse_context.begin();
    basic_format_specs<Char> specs;
    using internal::specs_handler;
    using parse_context_t = basic_format_parse_context<Char>;
    internal::specs_checker<specs_handler<parse_context_t, Context>> handler(
        specs_handler<parse_context_t, Context>(specs, parse_context, context),
        arg.type());
    begin = parse_format_specs(begin, end, handler);
    if (begin == end || *begin != '}') on_error("missing '}' in format string");
    advance_to(parse_context, begin);
    context.advance_to(
        visit_format_arg(ArgFormatter(context, &parse_context, &specs), arg));
    return begin;
  }

  basic_format_parse_context<Char> parse_context;
  Context context;
  basic_format_arg<Context> arg;
};

/** Formats arguments and writes the output to the range. */
template <typename ArgFormatter, typename Char, typename Context>
typename Context::iterator vformat_to(
    typename ArgFormatter::range out, basic_string_view<Char> format_str,
    basic_format_args<Context> args,
    internal::locale_ref loc = internal::locale_ref()) {
  format_handler<ArgFormatter, Char, Context> h(out, format_str, args, loc);
  internal::parse_format_string<false>(format_str, h);
  return h.context.out();
}

// Casts ``p`` to ``const void*`` for pointer formatting.
// Example:
//   auto s = format("{}", ptr(p));
template <typename T> inline const void* ptr(const T* p) { return p; }
template <typename T> inline const void* ptr(const std::unique_ptr<T>& p) {
  return p.get();
}
template <typename T> inline const void* ptr(const std::shared_ptr<T>& p) {
  return p.get();
}

template <typename It, typename Char> struct arg_join : internal::view {
  It begin;
  It end;
  basic_string_view<Char> sep;

  arg_join(It b, It e, basic_string_view<Char> s) : begin(b), end(e), sep(s) {}
};

template <typename It, typename Char>
struct formatter<arg_join<It, Char>, Char>
    : formatter<typename std::iterator_traits<It>::value_type, Char> {
  template <typename FormatContext>
  auto format(const arg_join<It, Char>& value, FormatContext& ctx)
      -> decltype(ctx.out()) {
    using base = formatter<typename std::iterator_traits<It>::value_type, Char>;
    auto it = value.begin;
    auto out = ctx.out();
    if (it != value.end) {
      out = base::format(*it++, ctx);
      while (it != value.end) {
        out = std::copy(value.sep.begin(), value.sep.end(), out);
        ctx.advance_to(out);
        out = base::format(*it++, ctx);
      }
    }
    return out;
  }
};

/**
  Returns an object that formats the iterator range `[begin, end)` with elements
  separated by `sep`.
 */
template <typename It>
arg_join<It, char> join(It begin, It end, string_view sep) {
  return {begin, end, sep};
}

template <typename It>
arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {
  return {begin, end, sep};
}

/**
  \rst
  Returns an object that formats `range` with elements separated by `sep`.

  **Example**::

    std::vector<int> v = {1, 2, 3};
    fmt::print("{}", fmt::join(v, ", "));
    // Output: "1, 2, 3"
  \endrst
 */
template <typename Range>
arg_join<internal::iterator_t<const Range>, char> join(const Range& range,
                                                       string_view sep) {
  return join(std::begin(range), std::end(range), sep);
}

template <typename Range>
arg_join<internal::iterator_t<const Range>, wchar_t> join(const Range& range,
                                                          wstring_view sep) {
  return join(std::begin(range), std::end(range), sep);
}

/**
  \rst
  Converts *value* to ``std::string`` using the default format for type *T*.
  It doesn't support user-defined types with custom formatters.

  **Example**::

    #include <fmt/format.h>

    std::string answer = fmt::to_string(42);
  \endrst
 */
template <typename T> inline std::string to_string(const T& value) {
  return format("{}", value);
}

/**
  Converts *value* to ``std::wstring`` using the default format for type *T*.
 */
template <typename T> inline std::wstring to_wstring(const T& value) {
  return format(L"{}", value);
}

template <typename Char, std::size_t SIZE>
std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) {
  return std::basic_string<Char>(buf.data(), buf.size());
}

template <typename Char>
typename buffer_context<Char>::iterator internal::vformat_to(
    internal::buffer<Char>& buf, basic_string_view<Char> format_str,
    basic_format_args<buffer_context<Char>> args) {
  using range = buffer_range<Char>;
  return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str),
                                          args);
}

template <typename S, typename Char = char_t<S>,
          FMT_ENABLE_IF(internal::is_string<S>::value)>
inline typename buffer_context<Char>::iterator vformat_to(
    internal::buffer<Char>& buf, const S& format_str,
    basic_format_args<buffer_context<Char>> args) {
  return internal::vformat_to(buf, to_string_view(format_str), args);
}

template <typename S, typename... Args, std::size_t SIZE = inline_buffer_size,
          typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline typename buffer_context<Char>::iterator format_to(
    basic_memory_buffer<Char, SIZE>& buf, const S& format_str, Args&&... args) {
  internal::check_format_string<Args...>(format_str);
  using context = buffer_context<Char>;
  return internal::vformat_to(buf, to_string_view(format_str),
                              {make_format_args<context>(args...)});
}

template <typename OutputIt, typename Char = char>
using format_context_t = basic_format_context<OutputIt, Char>;

template <typename OutputIt, typename Char = char>
using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>;

template <typename S, typename OutputIt, typename... Args,
          FMT_ENABLE_IF(
              internal::is_output_iterator<OutputIt>::value &&
              !internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
inline OutputIt vformat_to(OutputIt out, const S& format_str,
                           format_args_t<OutputIt, char_t<S>> args) {
  using range = internal::output_range<OutputIt, char_t<S>>;
  return vformat_to<arg_formatter<range>>(range(out),
                                          to_string_view(format_str), args);
}

/**
 \rst
 Formats arguments, writes the result to the output iterator ``out`` and returns
 the iterator past the end of the output range.

 **Example**::

   std::vector<char> out;
   fmt::format_to(std::back_inserter(out), "{}", 42);
 \endrst
 */
template <typename OutputIt, typename S, typename... Args,
          FMT_ENABLE_IF(
              internal::is_output_iterator<OutputIt>::value &&
              !internal::is_contiguous_back_insert_iterator<OutputIt>::value &&
              internal::is_string<S>::value)>
inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) {
  internal::check_format_string<Args...>(format_str);
  using context = format_context_t<OutputIt, char_t<S>>;
  return vformat_to(out, to_string_view(format_str),
                    {make_format_args<context>(args...)});
}

template <typename OutputIt> struct format_to_n_result {
  /** Iterator past the end of the output range. */
  OutputIt out;
  /** Total (not truncated) output size. */
  std::size_t size;
};

template <typename OutputIt, typename Char = typename OutputIt::value_type>
using format_to_n_context =
    format_context_t<internal::truncating_iterator<OutputIt>, Char>;

template <typename OutputIt, typename Char = typename OutputIt::value_type>
using format_to_n_args = basic_format_args<format_to_n_context<OutputIt, Char>>;

template <typename OutputIt, typename Char, typename... Args>
inline format_arg_store<format_to_n_context<OutputIt, Char>, Args...>
make_format_to_n_args(const Args&... args) {
  return format_arg_store<format_to_n_context<OutputIt, Char>, Args...>(
      args...);
}

template <typename OutputIt, typename Char, typename... Args,
          FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
inline format_to_n_result<OutputIt> vformat_to_n(
    OutputIt out, std::size_t n, basic_string_view<Char> format_str,
    format_to_n_args<OutputIt, Char> args) {
  auto it = vformat_to(internal::truncating_iterator<OutputIt>(out, n),
                       format_str, args);
  return {it.base(), it.count()};
}

/**
 \rst
 Formats arguments, writes up to ``n`` characters of the result to the output
 iterator ``out`` and returns the total output size and the iterator past the
 end of the output range.
 \endrst
 */
template <typename OutputIt, typename S, typename... Args,
          FMT_ENABLE_IF(internal::is_string<S>::value&&
                            internal::is_output_iterator<OutputIt>::value)>
inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n,
                                                const S& format_str,
                                                const Args&... args) {
  internal::check_format_string<Args...>(format_str);
  using context = format_to_n_context<OutputIt, char_t<S>>;
  return vformat_to_n(out, n, to_string_view(format_str),
                      {make_format_args<context>(args...)});
}

template <typename Char>
inline std::basic_string<Char> internal::vformat(
    basic_string_view<Char> format_str,
    basic_format_args<buffer_context<Char>> args) {
  basic_memory_buffer<Char> buffer;
  internal::vformat_to(buffer, format_str, args);
  return to_string(buffer);
}

/**
  Returns the number of characters in the output of
  ``format(format_str, args...)``.
 */
template <typename... Args>
inline std::size_t formatted_size(string_view format_str, const Args&... args) {
  return format_to(internal::counting_iterator(), format_str, args...).count();
}

#if FMT_USE_USER_DEFINED_LITERALS
namespace internal {

#  if FMT_USE_UDL_TEMPLATE
template <typename Char, Char... CHARS> class udl_formatter {
 public:
  template <typename... Args>
  std::basic_string<Char> operator()(Args&&... args) const {
    FMT_CONSTEXPR_DECL Char s[] = {CHARS..., '\0'};
    FMT_CONSTEXPR_DECL bool invalid_format =
        do_check_format_string<Char, error_handler, remove_cvref_t<Args>...>(
            basic_string_view<Char>(s, sizeof...(CHARS)));
    (void)invalid_format;
    return format(s, std::forward<Args>(args)...);
  }
};
#  else
template <typename Char> struct udl_formatter {
  basic_string_view<Char> str;

  template <typename... Args>
  std::basic_string<Char> operator()(Args&&... args) const {
    return format(str, std::forward<Args>(args)...);
  }
};
#  endif  // FMT_USE_UDL_TEMPLATE

template <typename Char> struct udl_arg {
  basic_string_view<Char> str;

  template <typename T> named_arg<T, Char> operator=(T&& value) const {
    return {str, std::forward<T>(value)};
  }
};

}  // namespace internal

inline namespace literals {
#  if FMT_USE_UDL_TEMPLATE
template <typename Char, Char... CHARS>
FMT_CONSTEXPR internal::udl_formatter<Char, CHARS...> operator""_format() {
  return {};
}
#  else
/**
  \rst
  User-defined literal equivalent of :func:`fmt::format`.

  **Example**::

    using namespace fmt::literals;
    std::string message = "The answer is {}"_format(42);
  \endrst
 */
FMT_CONSTEXPR internal::udl_formatter<char> operator"" _format(const char* s,
                                                               std::size_t n) {
  return {{s, n}};
}
FMT_CONSTEXPR internal::udl_formatter<wchar_t> operator"" _format(
    const wchar_t* s, std::size_t n) {
  return {{s, n}};
}
#  endif  // FMT_USE_UDL_TEMPLATE

/**
  \rst
  User-defined literal equivalent of :func:`fmt::arg`.

  **Example**::

    using namespace fmt::literals;
    fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
  \endrst
 */
FMT_CONSTEXPR internal::udl_arg<char> operator"" _a(const char* s,
                                                    std::size_t n) {
  return {{s, n}};
}
FMT_CONSTEXPR internal::udl_arg<wchar_t> operator"" _a(const wchar_t* s,
                                                       std::size_t n) {
  return {{s, n}};
}
}  // namespace literals
#endif  // FMT_USE_USER_DEFINED_LITERALS
FMT_END_NAMESPACE

#define FMT_STRING_IMPL(s, ...)                                         \
  [] {                                                                  \
    struct str : duckdb_fmt::compile_string {                                  \
      using char_type = typename std::remove_cv<std::remove_pointer<    \
          typename std::decay<decltype(s)>::type>::type>::type;         \
      __VA_ARGS__ FMT_CONSTEXPR                                         \
      operator duckdb_fmt::basic_string_view<char_type>() const {              \
        return {s, sizeof(s) / sizeof(char_type) - 1};                  \
      }                                                                 \
    } result;                                                           \
    /* Suppress Qt Creator warning about unused operator. */            \
    (void)static_cast<duckdb_fmt::basic_string_view<typename str::char_type>>( \
        result);                                                        \
    return result;                                                      \
  }()

/**
  \rst
  Constructs a compile-time format string.

  **Example**::

    // A compile-time error because 'd' is an invalid specifier for strings.
    std::string s = format(FMT_STRING("{:d}"), "foo");
  \endrst
 */
#define FMT_STRING(s) FMT_STRING_IMPL(s, )

#if defined(FMT_STRING_ALIAS) && FMT_STRING_ALIAS
#  define fmt(s) FMT_STRING_IMPL(s, [[deprecated]])
#endif

#ifdef FMT_HEADER_ONLY
#  define FMT_FUNC inline
// #  include "format-inl.h"
#else
#  define FMT_FUNC
#endif

#endif  // FMT_FORMAT_H_


// LICENSE_CHANGE_END


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #1
// See the end of this file for a list

// Formatting library for C++ - legacy printf implementation
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.

#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_

#include <algorithm>  // std::max
#include <limits>     // std::numeric_limits



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #1
// See the end of this file for a list

// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.

#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_

#include <ostream>


FMT_BEGIN_NAMESPACE
namespace internal {

template <class Char> class formatbuf : public std::basic_streambuf<Char> {
 private:
  using int_type = typename std::basic_streambuf<Char>::int_type;
  using traits_type = typename std::basic_streambuf<Char>::traits_type;

  buffer<Char>& buffer_;

 public:
  formatbuf(buffer<Char>& buf) : buffer_(buf) {}

 protected:
  // The put-area is actually always empty. This makes the implementation
  // simpler and has the advantage that the streambuf and the buffer are always
  // in sync and sputc never writes into uninitialized memory. The obvious
  // disadvantage is that each call to sputc always results in a (virtual) call
  // to overflow. There is no disadvantage here for sputn since this always
  // results in a call to xsputn.

  int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
    if (!traits_type::eq_int_type(ch, traits_type::eof()))
      buffer_.push_back(static_cast<Char>(ch));
    return ch;
  }

  std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
    buffer_.append(s, s + count);
    return count;
  }
};

template <typename Char> struct test_stream : std::basic_ostream<Char> {
 private:
  // Hide all operator<< from std::basic_ostream<Char>.
  void_t<> operator<<(null<>);
  void_t<> operator<<(const Char*);

  template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
                                      !std::is_enum<T>::value)>
  void_t<> operator<<(T);
};

// Checks if T has a user-defined operator<< (e.g. not a member of
// std::ostream).
template <typename T, typename Char> class is_streamable {
 private:
  template <typename U>
  static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
                                              << std::declval<U>()),
                                     void_t<>>::value>
  test(int);

  template <typename> static std::false_type test(...);

  using result = decltype(test<T>(0));

 public:
  static const bool value = result::value;
};

// Write the content of buf to os.
template <typename Char>
void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
  const Char* buf_data = buf.data();
  using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
  unsigned_streamsize size = buf.size();
  unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
  do {
    unsigned_streamsize n = size <= max_size ? size : max_size;
    os.write(buf_data, static_cast<std::streamsize>(n));
    buf_data += n;
    size -= n;
  } while (size != 0);
}

template <typename Char, typename T>
void format_value(buffer<Char>& buf, const T& value,
                  locale_ref loc = locale_ref()) {
  formatbuf<Char> format_buf(buf);
  std::basic_ostream<Char> output(&format_buf);
  if (loc) output.imbue(loc.get<std::locale>());
  output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
  output << value;
  buf.resize(buf.size());
}

// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
    : formatter<basic_string_view<Char>, Char> {
  template <typename Context>
  auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
    basic_memory_buffer<Char> buffer;
    format_value(buffer, value, ctx.locale());
    basic_string_view<Char> str(buffer.data(), buffer.size());
    return formatter<basic_string_view<Char>, Char>::format(str, ctx);
  }
};
}  // namespace internal

template <typename Char>
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
            basic_format_args<buffer_context<Char>> args) {
  basic_memory_buffer<Char> buffer;
  internal::vformat_to(buffer, format_str, args);
  internal::write(os, buffer);
}

/**
  \rst
  Prints formatted data to the stream *os*.

  **Example**::

    fmt::print(cerr, "Don't {}!", "panic");
  \endrst
 */
template <typename S, typename... Args,
          typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
  vprint(os, to_string_view(format_str),
         {internal::make_args_checked<Args...>(format_str, args...)});
}
FMT_END_NAMESPACE

#endif  // FMT_OSTREAM_H_


// LICENSE_CHANGE_END


#ifdef min
#undef min
#endif

FMT_BEGIN_NAMESPACE
namespace internal {

// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned> struct int_checker {
  template <typename T> static bool fits_in_int(T value) {
    unsigned max = max_value<int>();
    return value <= max;
  }
  static bool fits_in_int(bool) { return true; }
};

template <> struct int_checker<true> {
  template <typename T> static bool fits_in_int(T value) {
    return value >= std::numeric_limits<int>::min() &&
           value <= max_value<int>();
  }
  static bool fits_in_int(int) { return true; }
};

class printf_precision_handler {
 public:
  template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  int operator()(T value) {
    if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
      FMT_THROW(duckdb::Exception("number is too big"));
    return (std::max)(static_cast<int>(value), 0);
  }

  template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
  int operator()(T) {
    FMT_THROW(duckdb::Exception("precision is not integer"));
    return 0;
  }
};

// An argument visitor that returns true iff arg is a zero integer.
class is_zero_int {
 public:
  template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  bool operator()(T value) {
    return value == 0;
  }

  template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
  bool operator()(T) {
    return false;
  }
};

template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};

template <> struct make_unsigned_or_bool<bool> { using type = bool; };

template <typename T, typename Context> class arg_converter {
 private:
  using char_type = typename Context::char_type;

  basic_format_arg<Context>& arg_;
  char_type type_;

 public:
  arg_converter(basic_format_arg<Context>& arg, char_type type)
      : arg_(arg), type_(type) {}

  void operator()(bool value) {
    if (type_ != 's') operator()<bool>(value);
  }

  template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
  void operator()(U value) {
    bool is_signed = type_ == 'd' || type_ == 'i';
    using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
    if (const_check(sizeof(target_type) <= sizeof(int))) {
      // Extra casts are used to silence warnings.
      if (is_signed) {
        arg_ = internal::make_arg<Context>(
            static_cast<int>(static_cast<target_type>(value)));
      } else {
        using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
        arg_ = internal::make_arg<Context>(
            static_cast<unsigned>(static_cast<unsigned_type>(value)));
      }
    } else {
      if (is_signed) {
        // glibc's printf doesn't sign extend arguments of smaller types:
        //   std::printf("%lld", -42);  // prints "4294967254"
        // but we don't have to do the same because it's a UB.
        arg_ = internal::make_arg<Context>(static_cast<long long>(value));
      } else {
        arg_ = internal::make_arg<Context>(
            static_cast<typename make_unsigned_or_bool<U>::type>(value));
      }
    }
  }

  template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)>
  void operator()(U) {}  // No conversion needed for non-integral types.
};

// Converts an integer argument to T for printf, if T is an integral type.
// If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned).
template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context>& arg, Char type) {
  visit_format_arg(arg_converter<T, Context>(arg, type), arg);
}

// Converts an integer argument to char for printf.
template <typename Context> class char_converter {
 private:
  basic_format_arg<Context>& arg_;

 public:
  explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}

  template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  void operator()(T value) {
    arg_ = internal::make_arg<Context>(
        static_cast<typename Context::char_type>(value));
  }

  template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
  void operator()(T) {}  // No conversion needed for non-integral types.
};

// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char> class printf_width_handler {
 private:
  using format_specs = basic_format_specs<Char>;

  format_specs& specs_;

 public:
  explicit printf_width_handler(format_specs& specs) : specs_(specs) {}

  template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  unsigned operator()(T value) {
    auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
    if (internal::is_negative(value)) {
      specs_.align = align::left;
      width = 0 - width;
    }
    unsigned int_max = max_value<int>();
    if (width > int_max) FMT_THROW(duckdb::Exception("number is too big"));
    return static_cast<unsigned>(width);
  }

  template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
  unsigned operator()(T) {
    FMT_THROW(duckdb::Exception("width is not integer"));
    return 0;
  }
};

template <typename Char, typename Context>
void printf(buffer<Char>& buf, basic_string_view<Char> format,
            basic_format_args<Context> args) {
  Context(std::back_inserter(buf), format, args).format();
}

template <typename OutputIt, typename Char, typename Context>
internal::truncating_iterator<OutputIt> printf(
    internal::truncating_iterator<OutputIt> it, basic_string_view<Char> format,
    basic_format_args<Context> args) {
  return Context(it, format, args).format();
}
}  // namespace internal

using internal::printf;  // For printing into memory_buffer.

template <typename Range> class printf_arg_formatter;

template <typename OutputIt, typename Char> class basic_printf_context;

/**
  \rst
  The ``printf`` argument formatter.
  \endrst
 */
template <typename Range>
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
 public:
  using iterator = typename Range::iterator;

 private:
  using char_type = typename Range::value_type;
  using base = internal::arg_formatter_base<Range>;
  using context_type = basic_printf_context<iterator, char_type>;

  context_type& context_;

  void write_null_pointer(char) {
    this->specs()->type = 0;
    this->write("(nil)");
  }

  void write_null_pointer(wchar_t) {
    this->specs()->type = 0;
    this->write(L"(nil)");
  }

 public:
  using format_specs = typename base::format_specs;

  /**
    \rst
    Constructs an argument formatter object.
    *buffer* is a reference to the output buffer and *specs* contains format
    specifier information for standard argument types.
    \endrst
   */
  printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
      : base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {}

  template <typename T, FMT_ENABLE_IF(duckdb_fmt::internal::is_integral<T>::value)>
  iterator operator()(T value) {
    // MSVC2013 fails to compile separate overloads for bool and char_type so
    // use std::is_same instead.
    if (std::is_same<T, bool>::value) {
      format_specs& fmt_specs = *this->specs();
      if (fmt_specs.type != 's') return base::operator()(value ? 1 : 0);
      fmt_specs.type = 0;
      this->write(value != 0);
    } else if (std::is_same<T, char_type>::value) {
      format_specs& fmt_specs = *this->specs();
      if (fmt_specs.type && fmt_specs.type != 'c')
        return (*this)(static_cast<int>(value));
      fmt_specs.sign = sign::none;
      fmt_specs.alt = false;
      fmt_specs.align = align::right;
      return base::operator()(value);
    } else {
      return base::operator()(value);
    }
    return this->out();
  }

  template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
  iterator operator()(T value) {
    return base::operator()(value);
  }

  /** Formats a null-terminated C string. */
  iterator operator()(const char* value) {
    if (value)
      base::operator()(value);
    else if (this->specs()->type == 'p')
      write_null_pointer(char_type());
    else
      this->write("(null)");
    return this->out();
  }

  /** Formats a null-terminated wide C string. */
  iterator operator()(const wchar_t* value) {
    if (value)
      base::operator()(value);
    else if (this->specs()->type == 'p')
      write_null_pointer(char_type());
    else
      this->write(L"(null)");
    return this->out();
  }

  iterator operator()(basic_string_view<char_type> value) {
    return base::operator()(value);
  }

  iterator operator()(monostate value) { return base::operator()(value); }

  /** Formats a pointer. */
  iterator operator()(const void* value) {
    if (value) return base::operator()(value);
    this->specs()->type = 0;
    write_null_pointer(char_type());
    return this->out();
  }

  /** Formats an argument of a custom (user-defined) type. */
  iterator operator()(typename basic_format_arg<context_type>::handle handle) {
    handle.format(context_.parse_context(), context_);
    return this->out();
  }
};

template <typename T> struct printf_formatter {
  template <typename ParseContext>
  auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
    return ctx.begin();
  }

  template <typename FormatContext>
  auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
    internal::format_value(internal::get_container(ctx.out()), value);
    return ctx.out();
  }
};

/** This template formats data and writes the output to a writer. */
template <typename OutputIt, typename Char> class basic_printf_context {
 public:
  /** The character type for the output. */
  using char_type = Char;
  using format_arg = basic_format_arg<basic_printf_context>;
  template <typename T> using formatter_type = printf_formatter<T>;

 private:
  using format_specs = basic_format_specs<char_type>;

  OutputIt out_;
  basic_format_args<basic_printf_context> args_;
  basic_format_parse_context<Char> parse_ctx_;

  static void parse_flags(format_specs& specs, const Char*& it,
                          const Char* end);

  // Returns the argument with specified index or, if arg_index is -1, the next
  // argument.
  format_arg get_arg(int arg_index = -1);

  // Parses argument index, flags and width and returns the argument index.
  int parse_header(const Char*& it, const Char* end, format_specs& specs);

 public:
  /**
   \rst
   Constructs a ``printf_context`` object. References to the arguments and
   the writer are stored in the context object so make sure they have
   appropriate lifetimes.
   \endrst
   */
  basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
                       basic_format_args<basic_printf_context> args)
      : out_(out), args_(args), parse_ctx_(format_str) {}

  OutputIt out() { return out_; }
  void advance_to(OutputIt it) { out_ = it; }

  format_arg arg(int id) const { return args_.get(id); }

  basic_format_parse_context<Char>& parse_context() { return parse_ctx_; }

  FMT_CONSTEXPR void on_error(const char* message) {
    parse_ctx_.on_error(message);
  }

  /** Formats stored arguments and writes the output to the range. */
  template <typename ArgFormatter = printf_arg_formatter<buffer_range<Char>>>
  OutputIt format();
};

template <typename OutputIt, typename Char>
void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
                                                       const Char*& it,
                                                       const Char* end) {
  for (; it != end; ++it) {
    switch (*it) {
    case '-':
      specs.align = align::left;
      break;
    case '+':
      specs.sign = sign::plus;
      break;
    case '0':
      specs.fill[0] = '0';
      break;
    case ' ':
      specs.sign = sign::space;
      break;
    case '#':
      specs.alt = true;
      break;
    default:
      return;
    }
  }
}

template <typename OutputIt, typename Char>
typename basic_printf_context<OutputIt, Char>::format_arg
basic_printf_context<OutputIt, Char>::get_arg(int arg_index) {
  if (arg_index < 0)
    arg_index = parse_ctx_.next_arg_id();
  else
    parse_ctx_.check_arg_id(--arg_index);
  return internal::get_arg(*this, arg_index);
}

template <typename OutputIt, typename Char>
int basic_printf_context<OutputIt, Char>::parse_header(
    const Char*& it, const Char* end, format_specs& specs) {
  int arg_index = -1;
  char_type c = *it;
  if (c >= '0' && c <= '9') {
    // Parse an argument index (if followed by '$') or a width possibly
    // preceded with '0' flag(s).
    internal::error_handler eh;
    int value = parse_nonnegative_int(it, end, eh);
    if (it != end && *it == '$') {  // value is an argument index
      ++it;
      arg_index = value;
    } else {
      if (c == '0') specs.fill[0] = '0';
      if (value != 0) {
        // Nonzero value means that we parsed width and don't need to
        // parse it or flags again, so return now.
        specs.width = value;
        return arg_index;
      }
    }
  }
  parse_flags(specs, it, end);
  // Parse width.
  if (it != end) {
    if (*it >= '0' && *it <= '9') {
      internal::error_handler eh;
      specs.width = parse_nonnegative_int(it, end, eh);
    } else if (*it == '*') {
      ++it;
      specs.width = static_cast<int>(visit_format_arg(
          internal::printf_width_handler<char_type>(specs), get_arg()));
    }
  }
  return arg_index;
}

template <typename OutputIt, typename Char>
template <typename ArgFormatter>
OutputIt basic_printf_context<OutputIt, Char>::format() {
  auto out = this->out();
  const Char* start = parse_ctx_.begin();
  const Char* end = parse_ctx_.end();
  auto it = start;
  while (it != end) {
    char_type c = *it++;
    if (c != '%') continue;
    if (it != end && *it == c) {
      out = std::copy(start, it, out);
      start = ++it;
      continue;
    }
    out = std::copy(start, it - 1, out);

    format_specs specs;
    specs.align = align::right;

    // Parse argument index, flags and width.
    int arg_index = parse_header(it, end, specs);
    if (arg_index == 0) on_error("argument index out of range");

    // Parse precision.
    if (it != end && *it == '.') {
      ++it;
      c = it != end ? *it : 0;
      if ('0' <= c && c <= '9') {
        internal::error_handler eh;
        specs.precision = parse_nonnegative_int(it, end, eh);
      } else if (c == '*') {
        ++it;
        specs.precision =
            static_cast<int>(visit_format_arg(internal::printf_precision_handler(), get_arg()));
      } else {
        specs.precision = 0;
      }
    }

    format_arg arg = get_arg(arg_index);
    if (specs.alt && visit_format_arg(internal::is_zero_int(), arg))
      specs.alt = false;
    if (specs.fill[0] == '0') {
      if (arg.is_arithmetic())
        specs.align = align::numeric;
      else
        specs.fill[0] = ' ';  // Ignore '0' flag for non-numeric types.
    }

    // Parse length and convert the argument to the required type.
    c = it != end ? *it++ : 0;
    char_type t = it != end ? *it : 0;
    using internal::convert_arg;
    switch (c) {
    case 'h':
      if (t == 'h') {
        ++it;
        t = it != end ? *it : 0;
        convert_arg<signed char>(arg, t);
      } else {
        convert_arg<short>(arg, t);
      }
      break;
    case 'l':
      if (t == 'l') {
        ++it;
        t = it != end ? *it : 0;
        convert_arg<long long>(arg, t);
      } else {
        convert_arg<long>(arg, t);
      }
      break;
    case 'j':
      convert_arg<intmax_t>(arg, t);
      break;
    case 'z':
      convert_arg<std::size_t>(arg, t);
      break;
    case 't':
      convert_arg<std::ptrdiff_t>(arg, t);
      break;
    case 'L':
      // printf produces garbage when 'L' is omitted for long double, no
      // need to do the same.
      break;
    default:
      --it;
      convert_arg<void>(arg, c);
    }

    // Parse type.
    if (it == end) FMT_THROW(duckdb::Exception("invalid format string"));
    specs.type = static_cast<char>(*it++);
    if (arg.is_integral()) {
      // Normalize type.
      switch (specs.type) {
      case 'i':
      case 'u':
        specs.type = 'd';
        break;
      case 'c':
        visit_format_arg(internal::char_converter<basic_printf_context>(arg),
                         arg);
        break;
      }
    }

    start = it;

    // Format argument.
    visit_format_arg(ArgFormatter(out, specs, *this), arg);
  }
  return std::copy(start, it, out);
}

template <typename Char>
using basic_printf_context_t =
    basic_printf_context<std::back_insert_iterator<internal::buffer<Char>>,
                         Char>;

using printf_context = basic_printf_context_t<char>;
using wprintf_context = basic_printf_context_t<wchar_t>;

using printf_args = basic_format_args<printf_context>;
using wprintf_args = basic_format_args<wprintf_context>;

/**
  \rst
  Constructs an `~fmt::format_arg_store` object that contains references to
  arguments and can be implicitly converted to `~fmt::printf_args`.
  \endrst
 */
template <typename... Args>
inline format_arg_store<printf_context, Args...> make_printf_args(
    const Args&... args) {
  return {args...};
}

/**
  \rst
  Constructs an `~fmt::format_arg_store` object that contains references to
  arguments and can be implicitly converted to `~fmt::wprintf_args`.
  \endrst
 */
template <typename... Args>
inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
    const Args&... args) {
  return {args...};
}

template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vsprintf(
    const S& format, basic_format_args<basic_printf_context_t<Char>> args) {
  basic_memory_buffer<Char> buffer;
  printf(buffer, to_string_view(format), args);
  return to_string(buffer);
}

/**
  \rst
  Formats arguments and returns the result as a string.

  **Example**::

    std::string message = fmt::sprintf("The answer is %d", 42);
  \endrst
*/
template <typename S, typename... Args,
          typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
  using context = basic_printf_context_t<Char>;
  return vsprintf(to_string_view(format), {make_format_args<context>(args...)});
}

template <typename S, typename Char = char_t<S>>
inline int vfprintf(std::FILE* f, const S& format,
                    basic_format_args<basic_printf_context_t<Char>> args) {
  basic_memory_buffer<Char> buffer;
  printf(buffer, to_string_view(format), args);
  std::size_t size = buffer.size();
  return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
             ? -1
             : static_cast<int>(size);
}

/**
  \rst
  Prints formatted data to the file *f*.

  **Example**::

    fmt::fprintf(stderr, "Don't %s!", "panic");
  \endrst
 */
template <typename S, typename... Args,
          typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
  using context = basic_printf_context_t<Char>;
  return vfprintf(f, to_string_view(format),
                  {make_format_args<context>(args...)});
}

template <typename S, typename Char = char_t<S>>
inline int vprintf(const S& format,
                   basic_format_args<basic_printf_context_t<Char>> args) {
  return vfprintf(stdout, to_string_view(format), args);
}

/**
  \rst
  Prints formatted data to ``stdout``.

  **Example**::

    fmt::printf("Elapsed time: %.2f seconds", 1.23);
  \endrst
 */
template <typename S, typename... Args,
          FMT_ENABLE_IF(internal::is_string<S>::value)>
inline int printf(const S& format_str, const Args&... args) {
  using context = basic_printf_context_t<char_t<S>>;
  return vprintf(to_string_view(format_str),
                 {make_format_args<context>(args...)});
}

template <typename S, typename Char = char_t<S>>
inline int vfprintf(std::basic_ostream<Char>& os, const S& format,
                    basic_format_args<basic_printf_context_t<Char>> args) {
  basic_memory_buffer<Char> buffer;
  printf(buffer, to_string_view(format), args);
  internal::write(os, buffer);
  return static_cast<int>(buffer.size());
}

/** Formats arguments and writes the output to the range. */
template <typename ArgFormatter, typename Char,
          typename Context =
              basic_printf_context<typename ArgFormatter::iterator, Char>>
typename ArgFormatter::iterator vprintf(internal::buffer<Char>& out,
                                        basic_string_view<Char> format_str,
                                        basic_format_args<Context> args) {
  typename ArgFormatter::iterator iter(out);
  Context(iter, format_str, args).template format<ArgFormatter>();
  return iter;
}

/**
  \rst
  Prints formatted data to the stream *os*.

  **Example**::

    fmt::fprintf(cerr, "Don't %s!", "panic");
  \endrst
 */
template <typename S, typename... Args, typename Char = char_t<S>>
inline int fprintf(std::basic_ostream<Char>& os, const S& format_str,
                   const Args&... args) {
  using context = basic_printf_context_t<Char>;
  return vfprintf(os, to_string_view(format_str),
                  {make_format_args<context>(args...)});
}
FMT_END_NAMESPACE

#endif  // FMT_PRINTF_H_


// LICENSE_CHANGE_END


#ifdef _WIN32

#ifndef NOMINMAX
#define NOMINMAX
#endif

#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_
#endif

#include <windows.h>

#undef CreateDirectory
#undef MoveFile
#undef RemoveDirectory

#endif
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/string_functions.hpp
//
//
//===----------------------------------------------------------------------===//






// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list

/*
 * Copyright (c) 2014-2019 Steven G. Johnson, Jiahao Chen, Peter Colberg, Tony Kelman, Scott P. Jones, and other contributors.
 * Copyright (c) 2009 Public Software Group e. V., Berlin, Germany
 *
 * 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.
 */


/**
 * @mainpage
 *
 * utf8proc is a free/open-source (MIT/expat licensed) C library
 * providing Unicode normalization, case-folding, and other operations
 * for strings in the UTF-8 encoding, supporting up-to-date Unicode versions.
 * See the utf8proc home page (http://julialang.org/utf8proc/)
 * for downloads and other information, or the source code on github
 * (https://github.com/JuliaLang/utf8proc).
 *
 * For the utf8proc API documentation, see: @ref utf8proc.h
 *
 * The features of utf8proc include:
 *
 * - Transformation of strings (@ref utf8proc_map) to:
 *    - decompose (@ref UTF8PROC_DECOMPOSE) or compose (@ref UTF8PROC_COMPOSE) Unicode combining characters (http://en.wikipedia.org/wiki/Combining_character)
 *    - canonicalize Unicode compatibility characters (@ref UTF8PROC_COMPAT)
 *    - strip "ignorable" (@ref UTF8PROC_IGNORE) characters, control characters (@ref UTF8PROC_STRIPCC), or combining characters such as accents (@ref UTF8PROC_STRIPMARK)
 *    - case-folding (@ref UTF8PROC_CASEFOLD)
 * - Unicode normalization: @ref utf8proc_NFD, @ref utf8proc_NFC, @ref utf8proc_NFKD, @ref utf8proc_NFKC
 * - Detecting grapheme boundaries (@ref utf8proc_grapheme_break and @ref UTF8PROC_CHARBOUND)
 * - Character-width computation: @ref utf8proc_charwidth
 * - Classification of characters by Unicode category: @ref utf8proc_category and @ref utf8proc_category_string
 * - Encode (@ref utf8proc_encode_char) and decode (@ref utf8proc_iterate) Unicode codepoints to/from UTF-8.
 */

/** @file */

#ifndef UTF8PROC_H
#define UTF8PROC_H

// DuckDB change:
#define UTF8PROC_STATIC

/** @name API version
 *
 * The utf8proc API version MAJOR.MINOR.PATCH, following
 * semantic-versioning rules (http://semver.org) based on API
 * compatibility.
 *
 * This is also returned at runtime by @ref utf8proc_version; however, the
 * runtime version may append a string like "-dev" to the version number
 * for prerelease versions.
 *
 * @note The shared-library version number in the Makefile
 *       (and CMakeLists.txt, and MANIFEST) may be different,
 *       being based on ABI compatibility rather than API compatibility.
 */
/** @{ */
/** The MAJOR version number (increased when backwards API compatibility is broken). */
#define UTF8PROC_VERSION_MAJOR 2
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
#define UTF8PROC_VERSION_MINOR 4
/** The PATCH version (increased for fixes that do not change the API). */
#define UTF8PROC_VERSION_PATCH 0
/** @} */

#include <stdlib.h>

#if defined(_MSC_VER) && _MSC_VER < 1800
// MSVC prior to 2013 lacked stdbool.h and inttypes.h
typedef signed char utf8proc_int8_t;
typedef unsigned char utf8proc_uint8_t;
typedef short utf8proc_int16_t;
typedef unsigned short utf8proc_uint16_t;
typedef int utf8proc_int32_t;
typedef unsigned int utf8proc_uint32_t;
#  ifdef _WIN64
typedef __int64 utf8proc_ssize_t;
typedef unsigned __int64 utf8proc_size_t;
#  else
typedef int utf8proc_ssize_t;
typedef unsigned int utf8proc_size_t;
#  endif
#  ifndef __cplusplus
// emulate C99 bool
typedef unsigned char utf8proc_bool;
#    ifndef __bool_true_false_are_defined
#      define false 0
#      define true 1
#      define __bool_true_false_are_defined 1
#    endif
#  else
typedef bool utf8proc_bool;
#  endif
#else
#  include <stddef.h>
#  include <stdbool.h>
#  include <inttypes.h>
#endif
#include <limits.h>

#define UTF8PROC_DLLEXPORT
// #ifdef UTF8PROC_STATIC
// #  define UTF8PROC_DLLEXPORT
// #else
// #  ifdef _WIN32
// #    ifdef UTF8PROC_EXPORTS
// #      define UTF8PROC_DLLEXPORT __declspec(dllexport)
// #    else
// #      define UTF8PROC_DLLEXPORT __declspec(dllimport)
// #    endif
// #  elif __GNUC__ >= 4
// #    define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default")))
// #  else
// #    define UTF8PROC_DLLEXPORT
// #  endif
// #endif

namespace duckdb {

typedef int8_t utf8proc_int8_t;
typedef uint8_t utf8proc_uint8_t;
typedef int16_t utf8proc_int16_t;
typedef uint16_t utf8proc_uint16_t;
typedef int32_t utf8proc_int32_t;
typedef uint32_t utf8proc_uint32_t;
typedef size_t utf8proc_size_t;
typedef ptrdiff_t utf8proc_ssize_t;
typedef bool utf8proc_bool;

//#ifdef __cplusplus
//extern "C" {
//#endif

/**
 * Option flags used by several functions in the library.
 */
typedef enum {
  /** The given UTF-8 input is NULL terminated. */
  UTF8PROC_NULLTERM  = (1<<0),
  /** Unicode Versioning Stability has to be respected. */
  UTF8PROC_STABLE    = (1<<1),
  /** Compatibility decomposition (i.e. formatting information is lost). */
  UTF8PROC_COMPAT    = (1<<2),
  /** Return a result with decomposed characters. */
  UTF8PROC_COMPOSE   = (1<<3),
  /** Return a result with decomposed characters. */
  UTF8PROC_DECOMPOSE = (1<<4),
  /** Strip "default ignorable characters" such as SOFT-HYPHEN or ZERO-WIDTH-SPACE. */
  UTF8PROC_IGNORE    = (1<<5),
  /** Return an error, if the input contains unassigned codepoints. */
  UTF8PROC_REJECTNA  = (1<<6),
  /**
   * Indicating that NLF-sequences (LF, CRLF, CR, NEL) are representing a
   * line break, and should be converted to the codepoint for line
   * separation (LS).
   */
  UTF8PROC_NLF2LS    = (1<<7),
  /**
   * Indicating that NLF-sequences are representing a paragraph break, and
   * should be converted to the codepoint for paragraph separation
   * (PS).
   */
  UTF8PROC_NLF2PS    = (1<<8),
  /** Indicating that the meaning of NLF-sequences is unknown. */
  UTF8PROC_NLF2LF    = (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS),
  /** Strips and/or convers control characters.
   *
   * NLF-sequences are transformed into space, except if one of the
   * NLF2LS/PS/LF options is given. HorizontalTab (HT) and FormFeed (FF)
   * are treated as a NLF-sequence in this case.  All other control
   * characters are simply removed.
   */
  UTF8PROC_STRIPCC   = (1<<9),
  /**
   * Performs unicode case folding, to be able to do a case-insensitive
   * string comparison.
   */
  UTF8PROC_CASEFOLD  = (1<<10),
  /**
   * Inserts 0xFF bytes at the beginning of each sequence which is
   * representing a single grapheme cluster (see UAX#29).
   */
  UTF8PROC_CHARBOUND = (1<<11),
  /** Lumps certain characters together.
   *
   * E.g. HYPHEN U+2010 and MINUS U+2212 to ASCII "-". See lump.md for details.
   *
   * If NLF2LF is set, this includes a transformation of paragraph and
   * line separators to ASCII line-feed (LF).
   */
  UTF8PROC_LUMP      = (1<<12),
  /** Strips all character markings.
   *
   * This includes non-spacing, spacing and enclosing (i.e. accents).
   * @note This option works only with @ref UTF8PROC_COMPOSE or
   *       @ref UTF8PROC_DECOMPOSE
   */
  UTF8PROC_STRIPMARK = (1<<13),
  /**
   * Strip unassigned codepoints.
   */
  UTF8PROC_STRIPNA    = (1<<14),
} utf8proc_option_t;

/** @name Error codes
 * Error codes being returned by almost all functions.
 */
/** @{ */
/** Memory could not be allocated. */
#define UTF8PROC_ERROR_NOMEM -1
/** The given string is too long to be processed. */
#define UTF8PROC_ERROR_OVERFLOW -2
/** The given string is not a legal UTF-8 string. */
#define UTF8PROC_ERROR_INVALIDUTF8 -3
/** The @ref UTF8PROC_REJECTNA flag was set and an unassigned codepoint was found. */
#define UTF8PROC_ERROR_NOTASSIGNED -4
/** Invalid options have been used. */
#define UTF8PROC_ERROR_INVALIDOPTS -5
/** @} */

/* @name Types */

/** Holds the value of a property. */
typedef utf8proc_int16_t utf8proc_propval_t;

/** Struct containing information about a codepoint. */
typedef struct utf8proc_property_struct {
  /**
   * Unicode category.
   * @see utf8proc_category_t.
   */
  utf8proc_propval_t category;
  utf8proc_propval_t combining_class;
  /**
   * Bidirectional class.
   * @see utf8proc_bidi_class_t.
   */
  utf8proc_propval_t bidi_class;
  /**
   * @anchor Decomposition type.
   * @see utf8proc_decomp_type_t.
   */
  utf8proc_propval_t decomp_type;
  utf8proc_uint16_t decomp_seqindex;
  utf8proc_uint16_t casefold_seqindex;
  utf8proc_uint16_t uppercase_seqindex;
  utf8proc_uint16_t lowercase_seqindex;
  utf8proc_uint16_t titlecase_seqindex;
  utf8proc_uint16_t comb_index;
  unsigned bidi_mirrored:1;
  unsigned comp_exclusion:1;
  /**
   * Can this codepoint be ignored?
   *
   * Used by @ref utf8proc_decompose_char when @ref UTF8PROC_IGNORE is
   * passed as an option.
   */
  unsigned ignorable:1;
  unsigned control_boundary:1;
  /** The width of the codepoint. */
  unsigned charwidth:2;
  unsigned pad:2;
  /**
   * Boundclass.
   * @see utf8proc_boundclass_t.
   */
  unsigned boundclass:8;
} utf8proc_property_t;

/** Unicode categories. */
typedef enum {
  UTF8PROC_CATEGORY_CN  = 0, /**< Other, not assigned */
  UTF8PROC_CATEGORY_LU  = 1, /**< Letter, uppercase */
  UTF8PROC_CATEGORY_LL  = 2, /**< Letter, lowercase */
  UTF8PROC_CATEGORY_LT  = 3, /**< Letter, titlecase */
  UTF8PROC_CATEGORY_LM  = 4, /**< Letter, modifier */
  UTF8PROC_CATEGORY_LO  = 5, /**< Letter, other */
  UTF8PROC_CATEGORY_MN  = 6, /**< Mark, nonspacing */
  UTF8PROC_CATEGORY_MC  = 7, /**< Mark, spacing combining */
  UTF8PROC_CATEGORY_ME  = 8, /**< Mark, enclosing */
  UTF8PROC_CATEGORY_ND  = 9, /**< Number, decimal digit */
  UTF8PROC_CATEGORY_NL = 10, /**< Number, letter */
  UTF8PROC_CATEGORY_NO = 11, /**< Number, other */
  UTF8PROC_CATEGORY_PC = 12, /**< Punctuation, connector */
  UTF8PROC_CATEGORY_PD = 13, /**< Punctuation, dash */
  UTF8PROC_CATEGORY_PS = 14, /**< Punctuation, open */
  UTF8PROC_CATEGORY_PE = 15, /**< Punctuation, close */
  UTF8PROC_CATEGORY_PI = 16, /**< Punctuation, initial quote */
  UTF8PROC_CATEGORY_PF = 17, /**< Punctuation, final quote */
  UTF8PROC_CATEGORY_PO = 18, /**< Punctuation, other */
  UTF8PROC_CATEGORY_SM = 19, /**< Symbol, math */
  UTF8PROC_CATEGORY_SC = 20, /**< Symbol, currency */
  UTF8PROC_CATEGORY_SK = 21, /**< Symbol, modifier */
  UTF8PROC_CATEGORY_SO = 22, /**< Symbol, other */
  UTF8PROC_CATEGORY_ZS = 23, /**< Separator, space */
  UTF8PROC_CATEGORY_ZL = 24, /**< Separator, line */
  UTF8PROC_CATEGORY_ZP = 25, /**< Separator, paragraph */
  UTF8PROC_CATEGORY_CC = 26, /**< Other, control */
  UTF8PROC_CATEGORY_CF = 27, /**< Other, format */
  UTF8PROC_CATEGORY_CS = 28, /**< Other, surrogate */
  UTF8PROC_CATEGORY_CO = 29, /**< Other, private use */
} utf8proc_category_t;

/** Bidirectional character classes. */
typedef enum {
  UTF8PROC_BIDI_CLASS_L     = 1, /**< Left-to-Right */
  UTF8PROC_BIDI_CLASS_LRE   = 2, /**< Left-to-Right Embedding */
  UTF8PROC_BIDI_CLASS_LRO   = 3, /**< Left-to-Right Override */
  UTF8PROC_BIDI_CLASS_R     = 4, /**< Right-to-Left */
  UTF8PROC_BIDI_CLASS_AL    = 5, /**< Right-to-Left Arabic */
  UTF8PROC_BIDI_CLASS_RLE   = 6, /**< Right-to-Left Embedding */
  UTF8PROC_BIDI_CLASS_RLO   = 7, /**< Right-to-Left Override */
  UTF8PROC_BIDI_CLASS_PDF   = 8, /**< Pop Directional Format */
  UTF8PROC_BIDI_CLASS_EN    = 9, /**< European Number */
  UTF8PROC_BIDI_CLASS_ES   = 10, /**< European Separator */
  UTF8PROC_BIDI_CLASS_ET   = 11, /**< European Number Terminator */
  UTF8PROC_BIDI_CLASS_AN   = 12, /**< Arabic Number */
  UTF8PROC_BIDI_CLASS_CS   = 13, /**< Common Number Separator */
  UTF8PROC_BIDI_CLASS_NSM  = 14, /**< Nonspacing Mark */
  UTF8PROC_BIDI_CLASS_BN   = 15, /**< Boundary Neutral */
  UTF8PROC_BIDI_CLASS_B    = 16, /**< Paragraph Separator */
  UTF8PROC_BIDI_CLASS_S    = 17, /**< Segment Separator */
  UTF8PROC_BIDI_CLASS_WS   = 18, /**< Whitespace */
  UTF8PROC_BIDI_CLASS_ON   = 19, /**< Other Neutrals */
  UTF8PROC_BIDI_CLASS_LRI  = 20, /**< Left-to-Right Isolate */
  UTF8PROC_BIDI_CLASS_RLI  = 21, /**< Right-to-Left Isolate */
  UTF8PROC_BIDI_CLASS_FSI  = 22, /**< First Strong Isolate */
  UTF8PROC_BIDI_CLASS_PDI  = 23, /**< Pop Directional Isolate */
} utf8proc_bidi_class_t;

/** Decomposition type. */
typedef enum {
  UTF8PROC_DECOMP_TYPE_FONT      = 1, /**< Font */
  UTF8PROC_DECOMP_TYPE_NOBREAK   = 2, /**< Nobreak */
  UTF8PROC_DECOMP_TYPE_INITIAL   = 3, /**< Initial */
  UTF8PROC_DECOMP_TYPE_MEDIAL    = 4, /**< Medial */
  UTF8PROC_DECOMP_TYPE_FINAL     = 5, /**< Final */
  UTF8PROC_DECOMP_TYPE_ISOLATED  = 6, /**< Isolated */
  UTF8PROC_DECOMP_TYPE_CIRCLE    = 7, /**< Circle */
  UTF8PROC_DECOMP_TYPE_SUPER     = 8, /**< Super */
  UTF8PROC_DECOMP_TYPE_SUB       = 9, /**< Sub */
  UTF8PROC_DECOMP_TYPE_VERTICAL = 10, /**< Vertical */
  UTF8PROC_DECOMP_TYPE_WIDE     = 11, /**< Wide */
  UTF8PROC_DECOMP_TYPE_NARROW   = 12, /**< Narrow */
  UTF8PROC_DECOMP_TYPE_SMALL    = 13, /**< Small */
  UTF8PROC_DECOMP_TYPE_SQUARE   = 14, /**< Square */
  UTF8PROC_DECOMP_TYPE_FRACTION = 15, /**< Fraction */
  UTF8PROC_DECOMP_TYPE_COMPAT   = 16, /**< Compat */
} utf8proc_decomp_type_t;

/** Boundclass property. (TR29) */
typedef enum {
  UTF8PROC_BOUNDCLASS_START              =  0, /**< Start */
  UTF8PROC_BOUNDCLASS_OTHER              =  1, /**< Other */
  UTF8PROC_BOUNDCLASS_CR                 =  2, /**< Cr */
  UTF8PROC_BOUNDCLASS_LF                 =  3, /**< Lf */
  UTF8PROC_BOUNDCLASS_CONTROL            =  4, /**< Control */
  UTF8PROC_BOUNDCLASS_EXTEND             =  5, /**< Extend */
  UTF8PROC_BOUNDCLASS_L                  =  6, /**< L */
  UTF8PROC_BOUNDCLASS_V                  =  7, /**< V */
  UTF8PROC_BOUNDCLASS_T                  =  8, /**< T */
  UTF8PROC_BOUNDCLASS_LV                 =  9, /**< Lv */
  UTF8PROC_BOUNDCLASS_LVT                = 10, /**< Lvt */
  UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR = 11, /**< Regional indicator */
  UTF8PROC_BOUNDCLASS_SPACINGMARK        = 12, /**< Spacingmark */
  UTF8PROC_BOUNDCLASS_PREPEND            = 13, /**< Prepend */
  UTF8PROC_BOUNDCLASS_ZWJ                = 14, /**< Zero Width Joiner */

  /* the following are no longer used in Unicode 11, but we keep
     the constants here for backward compatibility */
  UTF8PROC_BOUNDCLASS_E_BASE             = 15, /**< Emoji Base */
  UTF8PROC_BOUNDCLASS_E_MODIFIER         = 16, /**< Emoji Modifier */
  UTF8PROC_BOUNDCLASS_GLUE_AFTER_ZWJ     = 17, /**< Glue_After_ZWJ */
  UTF8PROC_BOUNDCLASS_E_BASE_GAZ         = 18, /**< E_BASE + GLUE_AFTER_ZJW */

  /* the Extended_Pictographic property is used in the Unicode 11
     grapheme-boundary rules, so we store it in the boundclass field */
  UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC = 19,
  UTF8PROC_BOUNDCLASS_E_ZWG = 20, /* UTF8PROC_BOUNDCLASS_EXTENDED_PICTOGRAPHIC + ZWJ */
} utf8proc_boundclass_t;

/**
 * Function pointer type passed to @ref utf8proc_map_custom and
 * @ref utf8proc_decompose_custom, which is used to specify a user-defined
 * mapping of codepoints to be applied in conjunction with other mappings.
 */
typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data);

/**
 * Array containing the byte lengths of a UTF-8 encoded codepoint based
 * on the first byte.
 */
// UTF8PROC_DLLEXPORT extern const utf8proc_int8_t utf8proc_utf8class[256];

/**
 * Returns the utf8proc API version as a string MAJOR.MINOR.PATCH
 * (http://semver.org format), possibly with a "-dev" suffix for
 * development versions.
 */
UTF8PROC_DLLEXPORT const char *utf8proc_version(void);

/**
 * Returns the utf8proc supported Unicode version as a string MAJOR.MINOR.PATCH.
 */
UTF8PROC_DLLEXPORT const char *utf8proc_unicode_version(void);

/**
 * Returns an informative error string for the given utf8proc error code
 * (e.g. the error codes returned by @ref utf8proc_map).
 */
UTF8PROC_DLLEXPORT const char *utf8proc_errmsg(utf8proc_ssize_t errcode);

/**
 * Reads a single codepoint from the UTF-8 sequence being pointed to by `str`.
 * The maximum number of bytes read is `strlen`, unless `strlen` is
 * negative (in which case up to 4 bytes are read).
 *
 * If a valid codepoint could be read, it is stored in the variable
 * pointed to by `codepoint_ref`, otherwise that variable will be set to -1.
 * In case of success, the number of bytes read is returned; otherwise, a
 * negative error code is returned.
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_iterate(const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_int32_t *codepoint_ref);

/**
 * Check if a codepoint is valid (regardless of whether it has been
 * assigned a value by the current Unicode standard).
 *
 * @return 1 if the given `codepoint` is valid and otherwise return 0.
 */
UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_codepoint_valid(utf8proc_int32_t codepoint);

/**
 * Encodes the codepoint as an UTF-8 string in the byte array pointed
 * to by `dst`. This array must be at least 4 bytes long.
 *
 * In case of success the number of bytes written is returned, and
 * otherwise 0 is returned.
 *
 * This function does not check whether `codepoint` is valid Unicode.
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t codepoint, utf8proc_uint8_t *dst);

/**
 * Look up the properties for a given codepoint.
 *
 * @param codepoint The Unicode codepoint.
 *
 * @returns
 * A pointer to a (constant) struct containing information about
 * the codepoint.
 * @par
 * If the codepoint is unassigned or invalid, a pointer to a special struct is
 * returned in which `category` is 0 (@ref UTF8PROC_CATEGORY_CN).
 */
UTF8PROC_DLLEXPORT const utf8proc_property_t *utf8proc_get_property(utf8proc_int32_t codepoint);

/** Decompose a codepoint into an array of codepoints.
 *
 * @param codepoint the codepoint.
 * @param dst the destination buffer.
 * @param bufsize the size of the destination buffer.
 * @param options one or more of the following flags:
 * - @ref UTF8PROC_REJECTNA  - return an error `codepoint` is unassigned
 * - @ref UTF8PROC_IGNORE    - strip "default ignorable" codepoints
 * - @ref UTF8PROC_CASEFOLD  - apply Unicode casefolding
 * - @ref UTF8PROC_COMPAT    - replace certain codepoints with their
 *                             compatibility decomposition
 * - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster
 * - @ref UTF8PROC_LUMP      - lump certain different codepoints together
 * - @ref UTF8PROC_STRIPMARK - remove all character marks
 * - @ref UTF8PROC_STRIPNA   - remove unassigned codepoints
 * @param last_boundclass
 * Pointer to an integer variable containing
 * the previous codepoint's boundary class if the @ref UTF8PROC_CHARBOUND
 * option is used.  Otherwise, this parameter is ignored.
 *
 * @return
 * In case of success, the number of codepoints written is returned; in case
 * of an error, a negative error code is returned (@ref utf8proc_errmsg).
 * @par
 * If the number of written codepoints would be bigger than `bufsize`, the
 * required buffer size is returned, while the buffer will be overwritten with
 * undefined data.
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(
  utf8proc_int32_t codepoint, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize,
  utf8proc_option_t options, int *last_boundclass
);

/**
 * The same as @ref utf8proc_decompose_char, but acts on a whole UTF-8
 * string and orders the decomposed sequences correctly.
 *
 * If the @ref UTF8PROC_NULLTERM flag in `options` is set, processing
 * will be stopped, when a NULL byte is encounted, otherwise `strlen`
 * bytes are processed.  The result (in the form of 32-bit unicode
 * codepoints) is written into the buffer being pointed to by
 * `buffer` (which must contain at least `bufsize` entries).  In case of
 * success, the number of codepoints written is returned; in case of an
 * error, a negative error code is returned (@ref utf8proc_errmsg).
 * See @ref utf8proc_decompose_custom to supply additional transformations.
 *
 * If the number of written codepoints would be bigger than `bufsize`, the
 * required buffer size is returned, while the buffer will be overwritten with
 * undefined data.
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
  const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
  utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options
);

/**
 * The same as @ref utf8proc_decompose, but also takes a `custom_func` mapping function
 * that is called on each codepoint in `str` before any other transformations
 * (along with a `custom_data` pointer that is passed through to `custom_func`).
 * The `custom_func` argument is ignored if it is `NULL`.  See also @ref utf8proc_map_custom.
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
  const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
  utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
  utf8proc_custom_func custom_func, void *custom_data
);

/**
 * Normalizes the sequence of `length` codepoints pointed to by `buffer`
 * in-place (i.e., the result is also stored in `buffer`).
 *
 * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
 * @param length the length (in codepoints) of the buffer.
 * @param options a bitwise or (`|`) of one or more of the following flags:
 * - @ref UTF8PROC_NLF2LS  - convert LF, CRLF, CR and NEL into LS
 * - @ref UTF8PROC_NLF2PS  - convert LF, CRLF, CR and NEL into PS
 * - @ref UTF8PROC_NLF2LF  - convert LF, CRLF, CR and NEL into LF
 * - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters
 * - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite
 *                           codepoints
 * - @ref UTF8PROC_STABLE  - prohibit combining characters that would violate
 *                           the unicode versioning stability
 *
 * @return
 * In case of success, the length (in codepoints) of the normalized UTF-32 string is
 * returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
 *
 * @warning The entries of the array pointed to by `str` have to be in the
 *          range `0x0000` to `0x10FFFF`. Otherwise, the program might crash!
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options);

/**
 * Reencodes the sequence of `length` codepoints pointed to by `buffer`
 * UTF-8 data in-place (i.e., the result is also stored in `buffer`).
 * Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion.
 *
 * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
 * @param length the length (in codepoints) of the buffer.
 * @param options a bitwise or (`|`) of one or more of the following flags:
 * - @ref UTF8PROC_NLF2LS  - convert LF, CRLF, CR and NEL into LS
 * - @ref UTF8PROC_NLF2PS  - convert LF, CRLF, CR and NEL into PS
 * - @ref UTF8PROC_NLF2LF  - convert LF, CRLF, CR and NEL into LF
 * - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters
 * - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite
 *                           codepoints
 * - @ref UTF8PROC_STABLE  - prohibit combining characters that would violate
 *                           the unicode versioning stability
 * - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster
 *
 * @return
 * In case of success, the length (in bytes) of the resulting nul-terminated
 * UTF-8 string is returned; otherwise, a negative error code is returned
 * (@ref utf8proc_errmsg).
 *
 * @warning The amount of free space pointed to by `buffer` must
 *          exceed the amount of the input data by one byte, and the
 *          entries of the array pointed to by `str` have to be in the
 *          range `0x0000` to `0x10FFFF`. Otherwise, the program might crash!
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options);

/**
 * Given a pair of consecutive codepoints, return whether a grapheme break is
 * permitted between them (as defined by the extended grapheme clusters in UAX#29).
 *
 * @param codepoint1 The first codepoint.
 * @param codepoint2 The second codepoint, occurring consecutively after `codepoint1`.
 * @param state Beginning with Version 29 (Unicode 9.0.0), this algorithm requires
 *              state to break graphemes. This state can be passed in as a pointer
 *              in the `state` argument and should initially be set to 0. If the
 *              state is not passed in (i.e. a null pointer is passed), UAX#29 rules
 *              GB10/12/13 which require this state will not be applied, essentially
 *              matching the rules in Unicode 8.0.0.
 *
 * @warning If the state parameter is used, `utf8proc_grapheme_break_stateful` must
 *          be called IN ORDER on ALL potential breaks in a string.  However, it
 *          is safe to reset the state to zero after a grapheme break.
 */
UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break_stateful(
    utf8proc_int32_t codepoint1, utf8proc_int32_t codepoint2, utf8proc_int32_t *state);

/**
 * Same as @ref utf8proc_grapheme_break_stateful, except without support for the
 * Unicode 9 additions to the algorithm. Supported for legacy reasons.
 */
UTF8PROC_DLLEXPORT utf8proc_bool utf8proc_grapheme_break(
    utf8proc_int32_t codepoint1, utf8proc_int32_t codepoint2);

//! Returns the current UTF8 codepoint in a UTF8 string. Assumes the string is valid UTF8.
UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_codepoint(const char *u_input, int &sz);
UTF8PROC_DLLEXPORT utf8proc_bool grapheme_break_extended(int lbc, int tbc, utf8proc_int32_t *state);
UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_codepoint(const char *u_input, int &sz);
UTF8PROC_DLLEXPORT bool utf8proc_codepoint_to_utf8(int cp, int &sz, char *c);
UTF8PROC_DLLEXPORT int utf8proc_codepoint_length(int cp);
UTF8PROC_DLLEXPORT size_t utf8proc_next_grapheme(const char *s, size_t len, size_t cpos);
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_remove_accents(const utf8proc_uint8_t *str, utf8proc_ssize_t len);
template<class T>
void utf8proc_grapheme_callback(const char *s, size_t len, T &&fun) {
	int sz;
	int boundclass = UTF8PROC_BOUNDCLASS_START;
	int initial = utf8proc_get_property(utf8proc_codepoint(s, sz))->boundclass;
	grapheme_break_extended(boundclass, initial, &boundclass);
	size_t start = 0;
	size_t cpos = 0;
	while(true) {
		cpos += sz;
		if (cpos >= len) {
			fun(start, cpos);
			return;
		}
		int next = utf8proc_get_property(utf8proc_codepoint(s + cpos, sz))->boundclass;
		if (grapheme_break_extended(boundclass, next, &boundclass)) {
			if (!fun(start, cpos)) {
				return;
			}
			start = cpos;
		}
	}
}

/**
 * Given a codepoint `c`, return the codepoint of the corresponding
 * lower-case character, if any; otherwise (if there is no lower-case
 * variant, or if `c` is not a valid codepoint) return `c`.
 */
UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_tolower(utf8proc_int32_t c);

/**
 * Given a codepoint `c`, return the codepoint of the corresponding
 * upper-case character, if any; otherwise (if there is no upper-case
 * variant, or if `c` is not a valid codepoint) return `c`.
 */
UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_toupper(utf8proc_int32_t c);

/**
 * Given a codepoint `c`, return the codepoint of the corresponding
 * title-case character, if any; otherwise (if there is no title-case
 * variant, or if `c` is not a valid codepoint) return `c`.
 */
UTF8PROC_DLLEXPORT utf8proc_int32_t utf8proc_totitle(utf8proc_int32_t c);

/**
 * Given a codepoint, return a character width analogous to `wcwidth(codepoint)`,
 * except that a width of 0 is returned for non-printable codepoints
 * instead of -1 as in `wcwidth`.
 *
 * @note
 * If you want to check for particular types of non-printable characters,
 * (analogous to `isprint` or `iscntrl`), use @ref utf8proc_category. */
    UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t codepoint);

/**
 * Return the Unicode category for the codepoint (one of the
 * @ref utf8proc_category_t constants.)
 */
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t codepoint);

/**
 * Return the two-letter (nul-terminated) Unicode category string for
 * the codepoint (e.g. `"Lu"` or `"Co"`).
 */
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoint);

/**
 * Maps the given UTF-8 string pointed to by `str` to a new UTF-8
 * string, allocated dynamically by `malloc` and returned via `dstptr`.
 *
 * If the @ref UTF8PROC_NULLTERM flag in the `options` field is set,
 * the length is determined by a NULL terminator, otherwise the
 * parameter `strlen` is evaluated to determine the string length, but
 * in any case the result will be NULL terminated (though it might
 * contain NULL characters with the string if `str` contained NULL
 * characters). Other flags in the `options` field are passed to the
 * functions defined above, and regarded as described.  See also
 * @ref utf8proc_map_custom to supply a custom codepoint transformation.
 *
 * In case of success the length of the new string is returned,
 * otherwise a negative error code is returned.
 *
 * @note The memory of the new UTF-8 string will have been allocated
 * with `malloc`, and should therefore be deallocated with `free`.
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
  const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
);

/**
 * Like @ref utf8proc_map, but also takes a `custom_func` mapping function
 * that is called on each codepoint in `str` before any other transformations
 * (along with a `custom_data` pointer that is passed through to `custom_func`).
 * The `custom_func` argument is ignored if it is `NULL`.
 */
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
  const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
  utf8proc_custom_func custom_func, void *custom_data
);

/** @name Unicode normalization
 *
 * Returns a pointer to newly allocated memory of a NFD, NFC, NFKD, NFKC or
 * NFKC_Casefold normalized version of the null-terminated string `str`.  These
 * are shortcuts to calling @ref utf8proc_map with @ref UTF8PROC_NULLTERM
 * combined with @ref UTF8PROC_STABLE and flags indicating the normalization.
 */
/** @{ */
/** NFD normalization (@ref UTF8PROC_DECOMPOSE). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str, utf8proc_ssize_t len);
/** NFC normalization (@ref UTF8PROC_COMPOSE). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str, utf8proc_ssize_t len);
/** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str, utf8proc_ssize_t len);
/** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str, utf8proc_ssize_t len);
/**
 * NFKC_Casefold normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT
 * and @ref UTF8PROC_CASEFOLD and @ref UTF8PROC_IGNORE).
 **/
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC_Casefold(const utf8proc_uint8_t *str, utf8proc_ssize_t len);
/** @} */

//#ifdef __cplusplus
//}
//#endif
}
#endif


// LICENSE_CHANGE_END


namespace re2 {
class RE2;
}

namespace duckdb {

struct ReverseFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LowerFun {
	static uint8_t ascii_to_lower_map[];

	//! Returns the length of the result string obtained from lowercasing the given input (in bytes)
	static idx_t LowerLength(const char *input_data, idx_t input_length);
	//! Lowercases the string to the target output location, result_data must have space for at least LowerLength bytes
	static void LowerCase(const char *input_data, idx_t input_length, char *result_data);

	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct UpperFun {
	static uint8_t ascii_to_upper_map[];

	static void RegisterFunction(BuiltinFunctions &set);
};

struct StripAccentsFun {
	static bool IsAscii(const char *input, idx_t n);
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ConcatFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ConcatWSFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LengthFun {
	static void RegisterFunction(BuiltinFunctions &set);
	template <class TA, class TR>
	static inline TR Length(TA input) {
		auto input_data = input.GetDataUnsafe();
		auto input_length = input.GetSize();
		for (idx_t i = 0; i < input_length; i++) {
			if (input_data[i] & 0x80) {
				int64_t length = 0;
				// non-ascii character: use grapheme iterator on remainder of string
				utf8proc_grapheme_callback(input_data, input_length, [&](size_t start, size_t end) {
					length++;
					return true;
				});
				return length;
			}
		}
		return input_length;
	}
};

struct LikeFun {
	static void RegisterFunction(BuiltinFunctions &set);
	DUCKDB_API static bool Glob(const char *s, idx_t slen, const char *pattern, idx_t plen);
};

struct LikeEscapeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LpadFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LeftFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MD5Fun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct NFCNormalizeFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RightFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegexpFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SubstringFun {
	static void RegisterFunction(BuiltinFunctions &set);
	static string_t SubstringScalarFunction(Vector &result, string_t input, int64_t offset, int64_t length);
};

struct PrintfFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct InstrFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PrefixFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RepeatFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ReplaceFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RpadFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SuffixFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct TrimFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ContainsFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
	static idx_t Find(const string_t &haystack, const string_t &needle);
	static idx_t Find(const unsigned char *haystack, idx_t haystack_size, const unsigned char *needle,
	                  idx_t needle_size);
};

struct UnicodeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StringSplitFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ASCII {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CHR {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MismatchesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LevenshteinFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct JaccardFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/gzip_file_system.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class GZipFileSystem : public CompressedFileSystem {
	// 32 KB
	static constexpr const idx_t BUFFER_SIZE = 1 << 15;

public:
	unique_ptr<FileHandle> OpenCompressedFile(unique_ptr<FileHandle> handle, bool write) override;

	std::string GetName() const override {
		return "GZipFileSystem";
	}

	//! Verifies that a buffer contains a valid GZIP header
	static void VerifyGZIPHeader(uint8_t gzip_hdr[], idx_t read_count);
	//! Consumes a byte stream as a gzip string, returning the decompressed string
	static string UncompressGZIPString(const string &in);

	unique_ptr<StreamWrapper> CreateStream() override;
	idx_t InBufferSize() override;
	idx_t OutBufferSize() override;
};

static constexpr const uint8_t GZIP_COMPRESSION_DEFLATE = 0x08;

static constexpr const uint8_t GZIP_FLAG_ASCII = 0x1;
static constexpr const uint8_t GZIP_FLAG_MULTIPART = 0x2;
static constexpr const uint8_t GZIP_FLAG_EXTRA = 0x4;
static constexpr const uint8_t GZIP_FLAG_NAME = 0x8;
static constexpr const uint8_t GZIP_FLAG_COMMENT = 0x10;
static constexpr const uint8_t GZIP_FLAG_ENCRYPT = 0x20;

static constexpr const uint8_t GZIP_HEADER_MINSIZE = 10;

static constexpr const unsigned char GZIP_FLAG_UNSUPPORTED =
    GZIP_FLAG_ASCII | GZIP_FLAG_MULTIPART | GZIP_FLAG_EXTRA | GZIP_FLAG_COMMENT | GZIP_FLAG_ENCRYPT;

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #3
// See the end of this file for a list

/* miniz.c 2.0.8 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
   See "unlicense" statement at the end of this file.
   Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
   Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt

   Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define
   MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).

   * Low-level Deflate/Inflate implementation notes:

     Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or
     greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses
     approximately as well as zlib.

     Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function
     coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory
     block large enough to hold the entire file.

     The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation.

   * zlib-style API notes:

     miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in
     zlib replacement in many apps:
        The z_stream struct, optional memory allocation callbacks
        deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
        inflateInit/inflateInit2/inflate/inflateEnd
        compress, compress2, compressBound, uncompress
        CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines.
        Supports raw deflate streams or standard zlib streams with adler-32 checking.

     Limitations:
      The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries.
      I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but
      there are no guarantees that miniz.c pulls this off perfectly.

   * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by
     Alex Evans. Supports 1-4 bytes/pixel images.

   * ZIP archive API notes:

     The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to
     get the job done with minimal fuss. There are simple API's to retrieve file information, read files from
     existing archives, create new archives, append new files to existing archives, or clone archive data from
     one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h),
     or you can specify custom file read/write callbacks.

     - Archive reading: Just call this function to read a single file from a disk archive:

      void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name,
        size_t *pSize, mz_uint zip_flags);

     For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central
     directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files.

     - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file:

     int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);

     The locate operation can optionally check file comments too, which (as one example) can be used to identify
     multiple versions of the same file in an archive. This function uses a simple linear search through the central
     directory, so it's not very fast.

     Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and
     retrieve detailed info on each file by calling mz_zip_reader_file_stat().

     - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data
     to disk and builds an exact image of the central directory in memory. The central directory image is written
     all at once at the end of the archive file when the archive is finalized.

     The archive writer can optionally align each file's local header and file data to any power of 2 alignment,
     which can be useful when the archive will be read from optical media. Also, the writer supports placing
     arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still
     readable by any ZIP tool.

     - Archive appending: The simple way to add a single file to an archive is to call this function:

      mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name,
        const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);

     The archive will be created if it doesn't already exist, otherwise it'll be appended to.
     Note the appending is done in-place and is not an atomic operation, so if something goes wrong
     during the operation it's possible the archive could be left without a central directory (although the local
     file headers and file data will be fine, so the archive will be recoverable).

     For more complex archive modification scenarios:
     1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to
     preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the
     compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and
     you're done. This is safe but requires a bunch of temporary disk space or heap memory.

     2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(),
     append new files as needed, then finalize the archive which will write an updated central directory to the
     original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a
     possibility that the archive's central directory could be lost with this method if anything goes wrong, though.

     - ZIP archive support limitations:
     No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files.
     Requires streams capable of seeking.

   * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the
     below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.

   * Important: For best perf. be sure to customize the below macros for your target platform:
     #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
     #define MINIZ_LITTLE_ENDIAN 1
     #define MINIZ_HAS_64BIT_REGISTERS 1

   * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz
     uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files
     (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
*/





/* Defines to completely disable specific portions of miniz.c:
   If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */

/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */
#define MINIZ_NO_STDIO

/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */
/* get/set file times, and the C run-time funcs that get/set times won't be called. */
/* The current downside is the times written to your archives will be from 1979. */
#define MINIZ_NO_TIME

/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */
/* #define MINIZ_NO_ARCHIVE_APIS */

/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */
/* #define MINIZ_NO_ARCHIVE_WRITING_APIS */

/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */
/*#define MINIZ_NO_ZLIB_APIS */

/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES

/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
   Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
   callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
   functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */
/*#define MINIZ_NO_MALLOC */

#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */
#define MINIZ_NO_TIME
#endif

#include <stddef.h>



#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
#include <time.h>
#endif

#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */
#define MINIZ_X86_OR_X64_CPU 1
#else
#define MINIZ_X86_OR_X64_CPU 0
#endif

#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */
#define MINIZ_LITTLE_ENDIAN 1
#else
#define MINIZ_LITTLE_ENDIAN 0
#endif

#if MINIZ_X86_OR_X64_CPU
/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 // always 0 because alignment
#else
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
#endif

#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */
#define MINIZ_HAS_64BIT_REGISTERS 1
#else
#define MINIZ_HAS_64BIT_REGISTERS 0
#endif

namespace duckdb_miniz {

/* ------------------- zlib-style API Definitions. */

/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */
typedef unsigned long mz_ulong;

/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */
void mz_free(void *p);

#define MZ_ADLER32_INIT (1)
/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */
mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);

#define MZ_CRC32_INIT (0)
/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */
mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);

/* Compression strategies. */
enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 };

/* Method */
#define MZ_DEFLATED 8

/* Heap allocation callbacks.
Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */
typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
typedef void (*mz_free_func)(void *opaque, void *address);
typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);

/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */
enum {
	MZ_NO_COMPRESSION = 0,
	MZ_BEST_SPEED = 1,
	MZ_BEST_COMPRESSION = 9,
	MZ_UBER_COMPRESSION = 10,
	MZ_DEFAULT_LEVEL = 6,
	MZ_DEFAULT_COMPRESSION = -1
};

#define MZ_VERSION "10.0.3"
#define MZ_VERNUM 0xA030
#define MZ_VER_MAJOR 10
#define MZ_VER_MINOR 0
#define MZ_VER_REVISION 3
#define MZ_VER_SUBREVISION 0

#ifndef MINIZ_NO_ZLIB_APIS

/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */
enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };

/* Return status codes. MZ_PARAM_ERROR is non-standard. */
enum {
	MZ_OK = 0,
	MZ_STREAM_END = 1,
	MZ_NEED_DICT = 2,
	MZ_ERRNO = -1,
	MZ_STREAM_ERROR = -2,
	MZ_DATA_ERROR = -3,
	MZ_MEM_ERROR = -4,
	MZ_BUF_ERROR = -5,
	MZ_VERSION_ERROR = -6,
	MZ_PARAM_ERROR = -10000
};

/* Window bits */
#define MZ_DEFAULT_WINDOW_BITS 15

struct mz_internal_state;

/* Compression/decompression stream struct. */
typedef struct mz_stream_s {
	const unsigned char *next_in; /* pointer to next byte to read */
	unsigned int avail_in;        /* number of bytes available at next_in */
	mz_ulong total_in;            /* total number of bytes consumed so far */

	unsigned char *next_out; /* pointer to next byte to write */
	unsigned int avail_out;  /* number of bytes that can be written to next_out */
	mz_ulong total_out;      /* total number of bytes produced so far */

	char *msg;                       /* error msg (unused) */
	struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */

	mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */
	mz_free_func zfree;   /* optional heap free function (defaults to free) */
	void *opaque;         /* heap alloc function user pointer */

	int data_type;     /* data_type (unused) */
	mz_ulong adler;    /* adler32 of the source or uncompressed data */
	mz_ulong reserved; /* not used */
} mz_stream;

typedef mz_stream *mz_streamp;

/* Returns the version string of miniz.c. */
const char *mz_version(void);

/* mz_deflateInit() initializes a compressor with default options: */
/* Parameters: */
/*  pStream must point to an initialized mz_stream struct. */
/*  level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */
/*  level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio.
 */
/*  (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */
/* Return values: */
/*  MZ_OK on success. */
/*  MZ_STREAM_ERROR if the stream is bogus. */
/*  MZ_PARAM_ERROR if the input parameters are bogus. */
/*  MZ_MEM_ERROR on out of memory. */
int mz_deflateInit(mz_streamp pStream, int level);

/* mz_deflateInit2() is like mz_deflate(), except with more control: */
/* Additional parameters: */
/*   method must be MZ_DEFLATED */
/*   window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */
/*   mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */
int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);

/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */
int mz_deflateReset(mz_streamp pStream);

/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible.
 */
/* Parameters: */
/*   pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */
/*   flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */
/* Return values: */
/*   MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */
/*   MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */
/*   MZ_STREAM_ERROR if the stream is bogus. */
/*   MZ_PARAM_ERROR if one of the parameters is invalid. */
/*   MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */
int mz_deflate(mz_streamp pStream, int flush);

/* mz_deflateEnd() deinitializes a compressor: */
/* Return values: */
/*  MZ_OK on success. */
/*  MZ_STREAM_ERROR if the stream is bogus. */
int mz_deflateEnd(mz_streamp pStream);

/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */
mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);

/* Single-call compression functions mz_compress() and mz_compress2(): */
/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */
int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len,
                 int level);

/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */
mz_ulong mz_compressBound(mz_ulong source_len);

/* Initializes a decompressor. */
int mz_inflateInit(mz_streamp pStream);

/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */
/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */
int mz_inflateInit2(mz_streamp pStream, int window_bits);

/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */
/* Parameters: */
/*   pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */
/*   flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */
/*   On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */
/*   MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */
/* Return values: */
/*   MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */
/*   MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */
/*   MZ_STREAM_ERROR if the stream is bogus. */
/*   MZ_DATA_ERROR if the deflate stream is invalid. */
/*   MZ_PARAM_ERROR if one of the parameters is invalid. */
/*   MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */
/*   with more input data, or with more room in the output buffer (except when using single call decompression, described above). */
int mz_inflate(mz_streamp pStream, int flush);

/* Deinitializes a decompressor. */
int mz_inflateEnd(mz_streamp pStream);

/* Single-call decompression. */
/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */
int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);

/* Returns a string description of the specified error code, or NULL if the error code is invalid. */
const char *mz_error(int err);

/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */
/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */
#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
typedef unsigned char Byte;
typedef unsigned int uInt;
typedef mz_ulong uLong;
typedef Byte Bytef;
typedef uInt uIntf;
typedef char charf;
typedef int intf;
typedef void *voidpf;
typedef uLong uLongf;
typedef void *voidp;
typedef void *const voidpc;
#define Z_NULL 0
#define Z_NO_FLUSH MZ_NO_FLUSH
#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
#define Z_FULL_FLUSH MZ_FULL_FLUSH
#define Z_FINISH MZ_FINISH
#define Z_BLOCK MZ_BLOCK
#define Z_OK MZ_OK
#define Z_STREAM_END MZ_STREAM_END
#define Z_NEED_DICT MZ_NEED_DICT
#define Z_ERRNO MZ_ERRNO
#define Z_STREAM_ERROR MZ_STREAM_ERROR
#define Z_DATA_ERROR MZ_DATA_ERROR
#define Z_MEM_ERROR MZ_MEM_ERROR
#define Z_BUF_ERROR MZ_BUF_ERROR
#define Z_VERSION_ERROR MZ_VERSION_ERROR
#define Z_PARAM_ERROR MZ_PARAM_ERROR
#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
#define Z_BEST_SPEED MZ_BEST_SPEED
#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
#define Z_FILTERED MZ_FILTERED
#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
#define Z_RLE MZ_RLE
#define Z_FIXED MZ_FIXED
#define Z_DEFLATED MZ_DEFLATED
#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
#define alloc_func mz_alloc_func
#define free_func mz_free_func
#define internal_state mz_internal_state
#define z_stream mz_stream
#define deflateInit mz_deflateInit
#define deflateInit2 mz_deflateInit2
#define deflateReset mz_deflateReset
#define deflate mz_deflate
#define deflateEnd mz_deflateEnd
#define deflateBound mz_deflateBound
#define compress mz_compress
#define compress2 mz_compress2
#define compressBound mz_compressBound
#define inflateInit mz_inflateInit
#define inflateInit2 mz_inflateInit2
#define inflate mz_inflate
#define inflateEnd mz_inflateEnd
#define uncompress mz_uncompress
#define crc32 mz_crc32
#define adler32 mz_adler32
#define MAX_WBITS 15
#define MAX_MEM_LEVEL 9
#define zError mz_error
#define ZLIB_VERSION MZ_VERSION
#define ZLIB_VERNUM MZ_VERNUM
#define ZLIB_VER_MAJOR MZ_VER_MAJOR
#define ZLIB_VER_MINOR MZ_VER_MINOR
#define ZLIB_VER_REVISION MZ_VER_REVISION
#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
#define zlibVersion mz_version
#define zlib_version mz_version()
#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */

#endif /* MINIZ_NO_ZLIB_APIS */

}


#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

namespace duckdb_miniz {

/* ------------------- Types and macros */
typedef unsigned char mz_uint8;
typedef signed short mz_int16;
typedef unsigned short mz_uint16;
typedef unsigned int mz_uint32;
typedef unsigned int mz_uint;
typedef int64_t mz_int64;
typedef uint64_t mz_uint64;
typedef int mz_bool;

#define MZ_FALSE (0)
#define MZ_TRUE (1)

/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */
#ifdef _MSC_VER
#define MZ_MACRO_END while (0, 0)
#else
#define MZ_MACRO_END while (0)
#endif

#ifdef MINIZ_NO_STDIO
#define MZ_FILE void *
#else
#include <stdio.h>
#define MZ_FILE FILE
#endif /* #ifdef MINIZ_NO_STDIO */

#ifdef MINIZ_NO_TIME
typedef struct mz_dummy_time_t_tag
{
    int m_dummy;
} mz_dummy_time_t;
#define MZ_TIME_T mz_dummy_time_t
#else
#define MZ_TIME_T time_t
#endif

#define MZ_ASSERT(x) assert(x)

#ifdef MINIZ_NO_MALLOC
#define MZ_MALLOC(x) NULL
#define MZ_FREE(x) (void)x, ((void)0)
#define MZ_REALLOC(p, x) NULL
#else
#define MZ_MALLOC(x) malloc(x)
#define MZ_FREE(x) free(x)
#define MZ_REALLOC(p, x) realloc(p, x)
#endif

#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))

#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
#else
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
#endif

#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U))

#ifdef _MSC_VER
#define MZ_FORCEINLINE __forceinline
#elif defined(__GNUC__)
#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__))
#else
#define MZ_FORCEINLINE inline
#endif

extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size);
extern void miniz_def_free_func(void *opaque, void *address);
extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size);

#define MZ_UINT16_MAX (0xFFFFU)
#define MZ_UINT32_MAX (0xFFFFFFFFU)





/* ------------------- Low-level Compression API Definitions */

/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */
#define TDEFL_LESS_MEMORY 0

/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */
/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */
enum
{
    TDEFL_HUFFMAN_ONLY = 0,
    TDEFL_DEFAULT_MAX_PROBES = 128,
    TDEFL_MAX_PROBES_MASK = 0xFFF
};

/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */
/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */
/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */
/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */
/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */
/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */
/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */
/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */
/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */
enum
{
    TDEFL_WRITE_ZLIB_HEADER = 0x01000,
    TDEFL_COMPUTE_ADLER32 = 0x02000,
    TDEFL_GREEDY_PARSING_FLAG = 0x04000,
    TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
    TDEFL_RLE_MATCHES = 0x10000,
    TDEFL_FILTER_MATCHES = 0x20000,
    TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
    TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
};

/* High level compression functions: */
/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */
/* On entry: */
/*  pSrc_buf, src_buf_len: Pointer and size of source block to compress. */
/*  flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */
/* On return: */
/*  Function returns a pointer to the compressed data, or NULL on failure. */
/*  *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */
/*  The caller must free() the returned block when it's no longer needed. */
void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);

/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */
/* Returns 0 on failure. */
size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);

/* Compresses an image to a compressed PNG file in memory. */
/* On entry: */
/*  pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */
/*  The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */
/*  level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */
/*  If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */
/* On return: */
/*  Function returns a pointer to the compressed data, or NULL on failure. */
/*  *pLen_out will be set to the size of the PNG image file. */
/*  The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */
void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip);
void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out);

/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */
typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);

/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */
mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);

enum
{
    TDEFL_MAX_HUFF_TABLES = 3,
    TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
    TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
    TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
    TDEFL_LZ_DICT_SIZE = 32768,
    TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
    TDEFL_MIN_MATCH_LEN = 3,
    TDEFL_MAX_MATCH_LEN = 258
};

/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */
#if TDEFL_LESS_MEMORY
enum
{
    TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
    TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
    TDEFL_MAX_HUFF_SYMBOLS = 288,
    TDEFL_LZ_HASH_BITS = 12,
    TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
    TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
    TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
};
#else
enum
{
    TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
    TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
    TDEFL_MAX_HUFF_SYMBOLS = 288,
    TDEFL_LZ_HASH_BITS = 15,
    TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
    TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
    TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
};
#endif

/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */
typedef enum {
    TDEFL_STATUS_BAD_PARAM = -2,
    TDEFL_STATUS_PUT_BUF_FAILED = -1,
    TDEFL_STATUS_OKAY = 0,
    TDEFL_STATUS_DONE = 1
} tdefl_status;

/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */
typedef enum {
    TDEFL_NO_FLUSH = 0,
    TDEFL_SYNC_FLUSH = 2,
    TDEFL_FULL_FLUSH = 3,
    TDEFL_FINISH = 4
} tdefl_flush;

/* tdefl's compression state structure. */
typedef struct
{
    tdefl_put_buf_func_ptr m_pPut_buf_func;
    void *m_pPut_buf_user;
    mz_uint m_flags, m_max_probes[2];
    int m_greedy_parsing;
    mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
    mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
    mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
    mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
    tdefl_status m_prev_return_status;
    const void *m_pIn_buf;
    void *m_pOut_buf;
    size_t *m_pIn_buf_size, *m_pOut_buf_size;
    tdefl_flush m_flush;
    const mz_uint8 *m_pSrc;
    size_t m_src_buf_left, m_out_buf_ofs;
    mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
    mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
    mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
    mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
    mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
    mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
    mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
    mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
} tdefl_compressor;

/* Initializes the compressor. */
/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */
/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */
/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */
/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */
tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);

/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */
tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);

/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */
/* tdefl_compress_buffer() always consumes the entire input buffer. */
tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);

tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
mz_uint32 tdefl_get_adler32(tdefl_compressor *d);

/* Create tdefl_compress() flags given zlib-style compression parameters. */
/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */
/* window_bits may be -15 (raw deflate) or 15 (zlib) */
/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */
mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);

/* Allocate the tdefl_compressor structure in C so that */
/* non-C language bindings to tdefl_ API don't need to worry about */
/* structure size and allocation mechanism. */
tdefl_compressor *tdefl_compressor_alloc();
void tdefl_compressor_free(tdefl_compressor *pComp);




/* ------------------- Low-level Decompression API Definitions */


/* Decompression flags used by tinfl_decompress(). */
/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */
/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */
/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */
/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */
enum
{
    TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
    TINFL_FLAG_HAS_MORE_INPUT = 2,
    TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
    TINFL_FLAG_COMPUTE_ADLER32 = 8
};

/* High level decompression functions: */
/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */
/* On entry: */
/*  pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */
/* On return: */
/*  Function returns a pointer to the decompressed data, or NULL on failure. */
/*  *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */
/*  The caller must call mz_free() on the returned block when it's no longer needed. */
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);

/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */
/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);

/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */
/* Returns 1 on success or 0 on failure. */
typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);

struct tinfl_decompressor_tag;
typedef struct tinfl_decompressor_tag tinfl_decompressor;

/* Allocate the tinfl_decompressor structure in C so that */
/* non-C language bindings to tinfl_ API don't need to worry about */
/* structure size and allocation mechanism. */

tinfl_decompressor *tinfl_decompressor_alloc();
void tinfl_decompressor_free(tinfl_decompressor *pDecomp);

/* Max size of LZ dictionary. */
#define TINFL_LZ_DICT_SIZE 32768

/* Return status. */
typedef enum {
    /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */
    /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */
    /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */
    TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4,

    /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */
    TINFL_STATUS_BAD_PARAM = -3,

    /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */
    TINFL_STATUS_ADLER32_MISMATCH = -2,

    /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */
    TINFL_STATUS_FAILED = -1,

    /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */

    /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */
    /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */
    TINFL_STATUS_DONE = 0,

    /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */
    /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */
    /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */
    TINFL_STATUS_NEEDS_MORE_INPUT = 1,

    /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */
    /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */
    /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */
    /* so I may need to add some code to address this. */
    TINFL_STATUS_HAS_MORE_OUTPUT = 2
} tinfl_status;

/* Initializes the decompressor to its initial state. */
#define tinfl_init(r)     \
    do                    \
    {                     \
        (r)->m_state = 0; \
    }                     \
    MZ_MACRO_END
#define tinfl_get_adler32(r) (r)->m_check_adler32

/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */
/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);

/* Internal/private bits follow. */
enum
{
    TINFL_MAX_HUFF_TABLES = 3,
    TINFL_MAX_HUFF_SYMBOLS_0 = 288,
    TINFL_MAX_HUFF_SYMBOLS_1 = 32,
    TINFL_MAX_HUFF_SYMBOLS_2 = 19,
    TINFL_FAST_LOOKUP_BITS = 10,
    TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
};

typedef struct
{
    mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
    mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
} tinfl_huff_table;

#if MINIZ_HAS_64BIT_REGISTERS
#define TINFL_USE_64BIT_BITBUF 1
#else
#define TINFL_USE_64BIT_BITBUF 0
#endif

#if TINFL_USE_64BIT_BITBUF
typedef mz_uint64 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (64)
#else
typedef mz_uint32 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (32)
#endif

struct tinfl_decompressor_tag
{
    mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
    tinfl_bit_buf_t m_bit_buf;
    size_t m_dist_from_out_buf_start;
    tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
    mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
};






/* ------------------- ZIP archive reading/writing */

#ifndef MINIZ_NO_ARCHIVE_APIS


enum
{
    /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */
    MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
    MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512,
    MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512
};

typedef struct
{
    /* Central directory file index. */
    mz_uint32 m_file_index;

    /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */
    mz_uint64 m_central_dir_ofs;

    /* These fields are copied directly from the zip's central dir. */
    mz_uint16 m_version_made_by;
    mz_uint16 m_version_needed;
    mz_uint16 m_bit_flag;
    mz_uint16 m_method;

#ifndef MINIZ_NO_TIME
    MZ_TIME_T m_time;
#endif

    /* CRC-32 of uncompressed data. */
    mz_uint32 m_crc32;

    /* File's compressed size. */
    mz_uint64 m_comp_size;

    /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */
    mz_uint64 m_uncomp_size;

    /* Zip internal and external file attributes. */
    mz_uint16 m_internal_attr;
    mz_uint32 m_external_attr;

    /* Entry's local header file offset in bytes. */
    mz_uint64 m_local_header_ofs;

    /* Size of comment in bytes. */
    mz_uint32 m_comment_size;

    /* MZ_TRUE if the entry appears to be a directory. */
    mz_bool m_is_directory;

    /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */
    mz_bool m_is_encrypted;

    /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */
    mz_bool m_is_supported;

    /* Filename. If string ends in '/' it's a subdirectory entry. */
    /* Guaranteed to be zero terminated, may be truncated to fit. */
    char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];

    /* Comment field. */
    /* Guaranteed to be zero terminated, may be truncated to fit. */
    char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];

} mz_zip_archive_file_stat;

typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);
typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);
typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);

struct mz_zip_internal_state_tag;
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;

typedef enum {
    MZ_ZIP_MODE_INVALID = 0,
    MZ_ZIP_MODE_READING = 1,
    MZ_ZIP_MODE_WRITING = 2,
    MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
} mz_zip_mode;

typedef enum {
    MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
    MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
    MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
    MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800,
    MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */
    MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000,     /* validate the local headers, but don't decompress the entire file and check the crc32 */
    MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000,               /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */
    MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000,
    MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000
} mz_zip_flags;

typedef enum {
    MZ_ZIP_TYPE_INVALID = 0,
    MZ_ZIP_TYPE_USER,
    MZ_ZIP_TYPE_MEMORY,
    MZ_ZIP_TYPE_HEAP,
    MZ_ZIP_TYPE_FILE,
    MZ_ZIP_TYPE_CFILE,
    MZ_ZIP_TOTAL_TYPES
} mz_zip_type;

/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */
typedef enum {
    MZ_ZIP_NO_ERROR = 0,
    MZ_ZIP_UNDEFINED_ERROR,
    MZ_ZIP_TOO_MANY_FILES,
    MZ_ZIP_FILE_TOO_LARGE,
    MZ_ZIP_UNSUPPORTED_METHOD,
    MZ_ZIP_UNSUPPORTED_ENCRYPTION,
    MZ_ZIP_UNSUPPORTED_FEATURE,
    MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
    MZ_ZIP_NOT_AN_ARCHIVE,
    MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
    MZ_ZIP_UNSUPPORTED_MULTIDISK,
    MZ_ZIP_DECOMPRESSION_FAILED,
    MZ_ZIP_COMPRESSION_FAILED,
    MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
    MZ_ZIP_CRC_CHECK_FAILED,
    MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
    MZ_ZIP_ALLOC_FAILED,
    MZ_ZIP_FILE_OPEN_FAILED,
    MZ_ZIP_FILE_CREATE_FAILED,
    MZ_ZIP_FILE_WRITE_FAILED,
    MZ_ZIP_FILE_READ_FAILED,
    MZ_ZIP_FILE_CLOSE_FAILED,
    MZ_ZIP_FILE_SEEK_FAILED,
    MZ_ZIP_FILE_STAT_FAILED,
    MZ_ZIP_INVALID_PARAMETER,
    MZ_ZIP_INVALID_FILENAME,
    MZ_ZIP_BUF_TOO_SMALL,
    MZ_ZIP_INTERNAL_ERROR,
    MZ_ZIP_FILE_NOT_FOUND,
    MZ_ZIP_ARCHIVE_TOO_LARGE,
    MZ_ZIP_VALIDATION_FAILED,
    MZ_ZIP_WRITE_CALLBACK_FAILED,
    MZ_ZIP_TOTAL_ERRORS
} mz_zip_error;

typedef struct
{
    mz_uint64 m_archive_size;
    mz_uint64 m_central_directory_file_ofs;

    /* We only support up to UINT32_MAX files in zip64 mode. */
    mz_uint32 m_total_files;
    mz_zip_mode m_zip_mode;
    mz_zip_type m_zip_type;
    mz_zip_error m_last_error;

    mz_uint64 m_file_offset_alignment;

    mz_alloc_func m_pAlloc;
    mz_free_func m_pFree;
    mz_realloc_func m_pRealloc;
    void *m_pAlloc_opaque;

    mz_file_read_func m_pRead;
    mz_file_write_func m_pWrite;
    mz_file_needs_keepalive m_pNeeds_keepalive;
    void *m_pIO_opaque;

    mz_zip_internal_state *m_pState;

} mz_zip_archive;

typedef struct
{
    mz_zip_archive *pZip;
    mz_uint flags;

    int status;
#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
    mz_uint file_crc32;
#endif
    mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs;
    mz_zip_archive_file_stat file_stat;
    void *pRead_buf;
    void *pWrite_buf;

    size_t out_blk_remain;

    tinfl_decompressor inflator;

} mz_zip_reader_extract_iter_state;

/* -------- ZIP reading */

/* Inits a ZIP archive reader. */
/* These functions read and validate the archive's central directory. */
mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags);

mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags);

#ifndef MINIZ_NO_STDIO
/* Read a archive from a disk file. */
/* file_start_ofs is the file offset where the archive actually begins, or 0. */
/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */
mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags);
mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size);

/* Read an archive from an already opened FILE, beginning at the current file position. */
/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */
/* The FILE will NOT be closed when mz_zip_reader_end() is called. */
mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags);
#endif

/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */
mz_bool mz_zip_reader_end(mz_zip_archive *pZip);

/* -------- ZIP reading or writing */

/* Clears a mz_zip_archive struct to all zeros. */
/* Important: This must be done before passing the struct to any mz_zip functions. */
void mz_zip_zero_struct(mz_zip_archive *pZip);

mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip);
mz_zip_type mz_zip_get_type(mz_zip_archive *pZip);

/* Returns the total number of files in the archive. */
mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);

mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip);
mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip);
MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip);

/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */
size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n);

/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */
/* Note that the m_last_error functionality is not thread safe. */
mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num);
mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip);
mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip);
mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip);
const char *mz_zip_get_error_string(mz_zip_error mz_err);

/* MZ_TRUE if the archive file entry is a directory entry. */
mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);

/* MZ_TRUE if the file is encrypted/strong encrypted. */
mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index);

/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */
mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index);

/* Retrieves the filename of an archive file entry. */
/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */
mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);

/* Attempts to locates a file in the archive's central directory. */
/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */
/* Returns -1 if the file cannot be found. */
int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index);

/* Returns detailed information about an archive file entry. */
mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat);

/* MZ_TRUE if the file is in zip64 format. */
/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */
mz_bool mz_zip_is_zip64(mz_zip_archive *pZip);

/* Returns the total central directory size in bytes. */
/* The current max supported size is <= MZ_UINT32_MAX. */
size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip);

/* Extracts a archive file to a memory buffer using no memory allocation. */
/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */
mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);

/* Extracts a archive file to a memory buffer. */
mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags);

/* Extracts a archive file to a dynamically allocated heap buffer. */
/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */
/* Returns NULL and sets the last error on failure. */
void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags);
void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags);

/* Extracts a archive file using a callback function to output the file's data. */
mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);

/* Extract a file iteratively */
mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags);
size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size);
mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState);

#ifndef MINIZ_NO_STDIO
/* Extracts a archive file to a disk file and sets its last accessed and modified times. */
/* This function only extracts files, not archive directory records. */
mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags);

/* Extracts a archive file starting at the current position in the destination FILE stream. */
mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags);
#endif

#if 0
/* TODO */
	typedef void *mz_zip_streaming_extract_state_ptr;
	mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
	uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
	uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
	mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs);
	size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);
	mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
#endif

/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */
/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */
mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);

/* Validates an entire archive by calling mz_zip_validate_file() on each file. */
mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags);

/* Misc utils/helpers, valid for ZIP reading or writing */
mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr);
mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr);

/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */
mz_bool mz_zip_end(mz_zip_archive *pZip);

/* -------- ZIP writing */

#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS

/* Inits a ZIP archive writer. */
/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/
/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/
mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags);

mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);
mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags);

#ifndef MINIZ_NO_STDIO
mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning);
mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags);
mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags);
#endif

/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */
/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */
/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */
/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */
/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */
/* the archive is finalized the file's central directory will be hosed. */
mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename);
mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags);

/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */
/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */
/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */
mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags);

/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */
/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */
mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
                                 mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);

mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
                                    mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
                                    const char *user_extra_data_central, mz_uint user_extra_data_central_len);

#ifndef MINIZ_NO_STDIO
/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */
/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */
mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);

/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */
mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add,
                                const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
                                const char *user_extra_data_central, mz_uint user_extra_data_central_len);
#endif

/* Adds a file to an archive by fully cloning the data from another archive. */
/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */
mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index);

/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */
/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */
/* An archive must be manually finalized by calling this function for it to be valid. */
mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);

/* Finalizes a heap archive, returning a poiner to the heap block and its size. */
/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */
mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize);

/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */
/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */
mz_bool mz_zip_writer_end(mz_zip_archive *pZip);

/* -------- Misc. high-level helper functions: */

/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */
/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */
/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */
/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */
mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr);

/* Reads a single file from an archive into a heap block. */
/* If pComment is not NULL, only the file with the specified comment will be extracted. */
/* Returns NULL on failure. */
void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags);
void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr);

#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */



#endif /* MINIZ_NO_ARCHIVE_APIS */

} // namespace duckdb_miniz


// LICENSE_CHANGE_END


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #3
// See the end of this file for a list

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// miniz_wrapper.hpp
//
//
//===----------------------------------------------------------------------===//




#include <string>
#include <stdexcept>

namespace duckdb {

enum class MiniZStreamType {
	MINIZ_TYPE_NONE,
	MINIZ_TYPE_INFLATE,
	MINIZ_TYPE_DEFLATE
};

struct MiniZStream {
	static constexpr uint8_t GZIP_HEADER_MINSIZE = 10;
	static constexpr uint8_t GZIP_FOOTER_SIZE = 8;
	static constexpr uint8_t GZIP_COMPRESSION_DEFLATE = 0x08;
	static constexpr unsigned char GZIP_FLAG_UNSUPPORTED = 0x1 | 0x2 | 0x4 | 0x10 | 0x20;

public:
	MiniZStream() : type(MiniZStreamType::MINIZ_TYPE_NONE) {
		memset(&stream, 0, sizeof(duckdb_miniz::mz_stream));
	}
	~MiniZStream() {
		switch(type) {
		case MiniZStreamType::MINIZ_TYPE_INFLATE:
			duckdb_miniz::mz_inflateEnd(&stream);
			break;
		case MiniZStreamType::MINIZ_TYPE_DEFLATE:
			duckdb_miniz::mz_deflateEnd(&stream);
			break;
		default:
			break;
		}
	}
	void FormatException(std::string error_msg) {
		throw std::runtime_error(error_msg);
	}
	void FormatException(const char *error_msg, int mz_ret) {
		auto err = duckdb_miniz::mz_error(mz_ret);
		FormatException(error_msg + std::string(": ") + (err ? err : "Unknown error code"));
	}
	void Decompress(const char *compressed_data, size_t compressed_size, char *out_data, size_t out_size) {
		auto mz_ret = mz_inflateInit2(&stream, -MZ_DEFAULT_WINDOW_BITS);
		if (mz_ret != duckdb_miniz::MZ_OK) {
			FormatException("Failed to initialize miniz", mz_ret);
		}
		type = MiniZStreamType::MINIZ_TYPE_INFLATE;

		if (compressed_size < GZIP_HEADER_MINSIZE) {
			FormatException("Failed to decompress GZIP block: compressed size is less than gzip header size");
		}
		auto gzip_hdr = (const unsigned char *)compressed_data;
		if (gzip_hdr[0] != 0x1F || gzip_hdr[1] != 0x8B || gzip_hdr[2] != GZIP_COMPRESSION_DEFLATE ||
		    gzip_hdr[3] & GZIP_FLAG_UNSUPPORTED) {
			FormatException("Input is invalid/unsupported GZIP stream");
		}

		stream.next_in = (const unsigned char *)compressed_data + GZIP_HEADER_MINSIZE;
		stream.avail_in = compressed_size - GZIP_HEADER_MINSIZE;
		stream.next_out = (unsigned char *)out_data;
		stream.avail_out = out_size;

		mz_ret = mz_inflate(&stream, duckdb_miniz::MZ_FINISH);
		if (mz_ret != duckdb_miniz::MZ_OK && mz_ret != duckdb_miniz::MZ_STREAM_END) {
			FormatException("Failed to decompress GZIP block", mz_ret);
		}
	}
	size_t MaxCompressedLength(size_t input_size) {
		return duckdb_miniz::mz_compressBound(input_size) + GZIP_HEADER_MINSIZE + GZIP_FOOTER_SIZE;
	}
	static void InitializeGZIPHeader(unsigned char *gzip_header) {
		memset(gzip_header, 0, GZIP_HEADER_MINSIZE);
		gzip_header[0] = 0x1F;
		gzip_header[1] = 0x8B;
		gzip_header[2] = GZIP_COMPRESSION_DEFLATE;
		gzip_header[3] = 0;
		gzip_header[4] = 0;
		gzip_header[5] = 0;
		gzip_header[6] = 0;
		gzip_header[7] = 0;
		gzip_header[8] = 0;
		gzip_header[9] = 0xFF;
	}

	static void InitializeGZIPFooter(unsigned char *gzip_footer, duckdb_miniz::mz_ulong crc, idx_t uncompressed_size) {
		gzip_footer[0] = crc & 0xFF;
		gzip_footer[1] = (crc >> 8) & 0xFF;
		gzip_footer[2] = (crc >> 16) & 0xFF;
		gzip_footer[3] = (crc >> 24) & 0xFF;
		gzip_footer[4] = uncompressed_size & 0xFF;
		gzip_footer[5] = (uncompressed_size >> 8) & 0xFF;
		gzip_footer[6] = (uncompressed_size >> 16) & 0xFF;
		gzip_footer[7] = (uncompressed_size >> 24) & 0xFF;
	}

	void Compress(const char *uncompressed_data, size_t uncompressed_size, char *out_data, size_t *out_size) {
		auto mz_ret = mz_deflateInit2(&stream, duckdb_miniz::MZ_DEFAULT_LEVEL, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 1, 0);
		if (mz_ret != duckdb_miniz::MZ_OK) {
			FormatException("Failed to initialize miniz", mz_ret);
		}
		type = MiniZStreamType::MINIZ_TYPE_DEFLATE;

		auto gzip_header = (unsigned char*) out_data;
		InitializeGZIPHeader(gzip_header);

		auto gzip_body = gzip_header + GZIP_HEADER_MINSIZE;

		stream.next_in = (const unsigned char*) uncompressed_data;
		stream.avail_in = uncompressed_size;
		stream.next_out = gzip_body;
		stream.avail_out = *out_size - GZIP_HEADER_MINSIZE;

		mz_ret = mz_deflate(&stream, duckdb_miniz::MZ_FINISH);
		if (mz_ret != duckdb_miniz::MZ_OK && mz_ret != duckdb_miniz::MZ_STREAM_END) {
			FormatException("Failed to compress GZIP block", mz_ret);
		}
		auto gzip_footer = gzip_body + stream.total_out;
		auto crc = duckdb_miniz::mz_crc32(MZ_CRC32_INIT, (const unsigned char*) uncompressed_data, uncompressed_size);
		InitializeGZIPFooter(gzip_footer, crc, uncompressed_size);

		*out_size = stream.total_out + GZIP_HEADER_MINSIZE + GZIP_FOOTER_SIZE;
	}

private:
	duckdb_miniz::mz_stream stream;
	MiniZStreamType type;
};

}


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





namespace duckdb {

class LocalFileSystem : public FileSystem {
public:
	unique_ptr<FileHandle> OpenFile(const string &path, uint8_t flags, FileLockType lock = FileLockType::NO_LOCK,
	                                FileCompressionType compression = FileCompressionType::UNCOMPRESSED,
	                                FileOpener *opener = nullptr) override;

	//! 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().
	void Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override;
	//! Write exactly nr_bytes to the specified location in the file. Fails if nr_bytes could not be read. This is
	//! equivalent to calling SetFilePointer(location) followed by calling Write().
	void Write(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override;
	//! Read nr_bytes from the specified file into the buffer, moving the file pointer forward by nr_bytes. Returns the
	//! amount of bytes read.
	int64_t Read(FileHandle &handle, void *buffer, int64_t nr_bytes) override;
	//! Write nr_bytes from the buffer into the file, moving the file pointer forward by nr_bytes.
	int64_t Write(FileHandle &handle, void *buffer, int64_t nr_bytes) override;

	//! Returns the file size of a file handle, returns -1 on error
	int64_t GetFileSize(FileHandle &handle) override;
	//! Returns the file last modified time of a file handle, returns timespec with zero on all attributes on error
	time_t GetLastModifiedTime(FileHandle &handle) override;
	//! Returns the file last modified time of a file handle, returns timespec with zero on all attributes on error
	FileType GetFileType(FileHandle &handle) override;
	//! 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
	void Truncate(FileHandle &handle, int64_t new_size) override;

	//! Check if a directory exists
	bool DirectoryExists(const string &directory) override;
	//! Create a directory if it does not exist
	void CreateDirectory(const string &directory) override;
	//! Recursively remove a directory and all files in it
	void RemoveDirectory(const string &directory) override;
	//! List files in a directory, invoking the callback method for each one with (filename, is_dir)
	bool ListFiles(const string &directory, const std::function<void(const string &, bool)> &callback) override;
	//! Move a file from source path to the target, StorageManager relies on this being an atomic action for ACID
	//! properties
	void MoveFile(const string &source, const string &target) override;
	//! Check if a file exists
	bool FileExists(const string &filename) override;

	//! Check if path is a pipe
	bool IsPipe(const string &filename) override;
	//! Remove a file from disk
	void RemoveFile(const string &filename) override;
	//! Sync a file handle to disk
	void FileSync(FileHandle &handle) override;

	//! Runs a glob on the file system, returning a list of matching files
	vector<string> Glob(const string &path, FileOpener *opener = nullptr) override;

	bool CanHandleFile(const string &fpath) override {
		//! Whether or not a sub-system can handle a specific file path
		return false;
	}

	//! Set the file pointer of a file handle to a specified location. Reads and writes will happen from this location
	void Seek(FileHandle &handle, idx_t location) override;
	//! Return the current seek posiiton in the file.
	idx_t SeekPosition(FileHandle &handle) override;

	//! Whether or not we can seek into the file
	bool CanSeek() override;
	//! 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
	bool OnDiskFile(FileHandle &handle) override;

	std::string GetName() const override {
		return "LocalFileSystem";
	}

	//! Returns the last Win32 error, in string format. Returns an empty string if there is no error, or on non-Windows
	//! systems.
	static std::string GetLastErrorAsString();

private:
	//! Set the file pointer of a file handle to a specified location. Reads and writes will happen from this location
	void SetFilePointer(FileHandle &handle, idx_t location);
	idx_t GetFilePointer(FileHandle &handle);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/file_opener.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class Value;

//! Abstract type that provide client-specific context to FileSystem.
class FileOpener {
public:
	virtual ~FileOpener() {};

	virtual bool TryGetCurrentSetting(const string &key, Value &result) = 0;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/windows_util.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

#ifdef DUCKDB_WINDOWS
class WindowsUtil {
public:
	//! Windows helper functions
	static std::wstring UTF8ToUnicode(const char *input);
	static string UnicodeToUTF8(LPCWSTR input);
	static string UTF8ToMBCS(const char *input, bool use_ansi = false);
};
#endif

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/cast_operators.hpp
//
//
//===----------------------------------------------------------------------===//








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







namespace duckdb {

struct ConvertToString {
	template <class SRC>
	static inline string Operation(SRC input) {
		throw InternalException("Unrecognized type for ConvertToString %s", GetTypeId<SRC>());
	}
};

template <>
string ConvertToString::Operation(bool input);
template <>
string ConvertToString::Operation(int8_t input);
template <>
string ConvertToString::Operation(int16_t input);
template <>
string ConvertToString::Operation(int32_t input);
template <>
string ConvertToString::Operation(int64_t input);
template <>
string ConvertToString::Operation(uint8_t input);
template <>
string ConvertToString::Operation(uint16_t input);
template <>
string ConvertToString::Operation(uint32_t input);
template <>
string ConvertToString::Operation(uint64_t input);
template <>
string ConvertToString::Operation(hugeint_t input);
template <>
string ConvertToString::Operation(float input);
template <>
string ConvertToString::Operation(double input);
template <>
string ConvertToString::Operation(interval_t input);
template <>
string ConvertToString::Operation(date_t input);
template <>
string ConvertToString::Operation(dtime_t input);
template <>
string ConvertToString::Operation(timestamp_t input);
template <>
string ConvertToString::Operation(string_t input);

} // namespace duckdb

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









#include <limits>
#include <cstring>
#include <cmath>

namespace duckdb {

//! Placeholder to insert in Vectors or to use for hashing NULLs
template <class T>
inline T NullValue() {
	return std::numeric_limits<T>::min();
}

constexpr const char str_nil[2] = {'\200', '\0'};

template <>
inline const char *NullValue() {
	D_ASSERT(str_nil[0] == '\200' && str_nil[1] == '\0');
	return str_nil;
}

template <>
inline string_t NullValue() {
	return string_t(NullValue<const char *>());
}

template <>
inline char *NullValue() {
	return (char *)NullValue<const char *>();
}

template <>
inline string NullValue() {
	return string(NullValue<const char *>());
}

template <>
inline interval_t NullValue() {
	interval_t null_value;
	null_value.days = NullValue<int32_t>();
	null_value.months = NullValue<int32_t>();
	null_value.micros = NullValue<int64_t>();
	return null_value;
}

template <>
inline hugeint_t NullValue() {
	hugeint_t min;
	min.lower = 0;
	min.upper = std::numeric_limits<int64_t>::min();
	return min;
}

template <>
inline float NullValue() {
	return NAN;
}

template <>
inline double NullValue() {
	return NAN;
}

} // namespace duckdb


namespace duckdb {
struct ValidityMask;
class Vector;

struct TryCast {
	template <class SRC, class DST>
	DUCKDB_API static inline bool Operation(SRC input, DST &result, bool strict = false) {
		throw NotImplementedException("Unimplemented type for cast (%s -> %s)", GetTypeId<SRC>(), GetTypeId<DST>());
	}
};

struct TryCastErrorMessage {
	template <class SRC, class DST>
	DUCKDB_API static inline bool Operation(SRC input, DST &result, string *error_message, bool strict = false) {
		throw NotImplementedException("Unimplemented type for cast (%s -> %s)", GetTypeId<SRC>(), GetTypeId<DST>());
	}
};

template <class SRC, class DST>
static string CastExceptionText(SRC input) {
	if (std::is_same<SRC, string_t>()) {
		return "Could not convert string '" + ConvertToString::Operation<SRC>(input) + "' to " +
		       TypeIdToString(GetTypeId<DST>());
	}
	if (TypeIsNumber<SRC>() && TypeIsNumber<DST>()) {
		return "Type " + TypeIdToString(GetTypeId<SRC>()) + " with value " + ConvertToString::Operation<SRC>(input) +
		       " can't be cast because the value is out of range for the destination type " +
		       TypeIdToString(GetTypeId<DST>());
	}
	return "Type " + TypeIdToString(GetTypeId<SRC>()) + " with value " + ConvertToString::Operation<SRC>(input) +
	       " can't be cast to the destination type " + TypeIdToString(GetTypeId<DST>());
}

struct Cast {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		DST result;
		if (!TryCast::Operation(input, result)) {
			throw InvalidInputException(CastExceptionText<SRC, DST>(input));
		}
		return result;
	}
};

struct HandleCastError {
	static void AssignError(string error_message, string *error_message_ptr) {
		if (!error_message_ptr) {
			throw ConversionException(error_message);
		}
		if (error_message_ptr->empty()) {
			*error_message_ptr = error_message;
		}
	}
};

//===--------------------------------------------------------------------===//
// Cast bool -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(bool input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(bool input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast int8_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int8_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast int16_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int16_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast int32_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int32_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast int64_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(int64_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast hugeint_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(hugeint_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast uint8_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint8_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast uint16_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint16_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast uint32_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint32_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast uint64_t -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(uint64_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast float -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(float input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(float input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Cast double -> Numeric
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(double input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(double input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// String -> Numeric Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(string_t input, bool &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, int8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, int16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, int32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, int64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, uint8_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, uint16_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, uint32_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, uint64_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, hugeint_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, float &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, double &result, bool strict);

//===--------------------------------------------------------------------===//
// Date Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(date_t input, date_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(date_t input, timestamp_t &result, bool strict);

//===--------------------------------------------------------------------===//
// Time Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(dtime_t input, dtime_t &result, bool strict);

//===--------------------------------------------------------------------===//
// Timestamp Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(timestamp_t input, date_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(timestamp_t input, dtime_t &result, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(timestamp_t input, timestamp_t &result, bool strict);

//===--------------------------------------------------------------------===//
// Interval Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCast::Operation(interval_t input, interval_t &result, bool strict);

//===--------------------------------------------------------------------===//
// String -> Date Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastErrorMessage::Operation(string_t input, date_t &result, string *error_message, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, date_t &result, bool strict);
template <>
date_t Cast::Operation(string_t input);
//===--------------------------------------------------------------------===//
// String -> Time Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastErrorMessage::Operation(string_t input, dtime_t &result, string *error_message, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, dtime_t &result, bool strict);
template <>
dtime_t Cast::Operation(string_t input);
//===--------------------------------------------------------------------===//
// String -> Timestamp Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastErrorMessage::Operation(string_t input, timestamp_t &result, string *error_message, bool strict);
template <>
DUCKDB_API bool TryCast::Operation(string_t input, timestamp_t &result, bool strict);
template <>
timestamp_t Cast::Operation(string_t input);
//===--------------------------------------------------------------------===//
// String -> Interval Casts
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastErrorMessage::Operation(string_t input, interval_t &result, string *error_message, bool strict);

//===--------------------------------------------------------------------===//
// string -> Non-Standard Timestamps
//===--------------------------------------------------------------------===//
struct TryCastToTimestampNS {
	template <class SRC, class DST>
	DUCKDB_API static inline bool Operation(SRC input, DST &result, bool strict = false) {
		throw InternalException("Unsupported type for try cast to timestamp (ns)");
	}
};

struct TryCastToTimestampMS {
	template <class SRC, class DST>
	DUCKDB_API static inline bool Operation(SRC input, DST &result, bool strict = false) {
		throw InternalException("Unsupported type for try cast to timestamp (ms)");
	}
};

struct TryCastToTimestampSec {
	template <class SRC, class DST>
	DUCKDB_API static inline bool Operation(SRC input, DST &result, bool strict = false) {
		throw InternalException("Unsupported type for try cast to timestamp (s)");
	}
};

template <>
DUCKDB_API bool TryCastToTimestampNS::Operation(string_t input, timestamp_t &result, bool strict);
template <>
DUCKDB_API bool TryCastToTimestampMS::Operation(string_t input, timestamp_t &result, bool strict);
template <>
DUCKDB_API bool TryCastToTimestampSec::Operation(string_t input, timestamp_t &result, bool strict);

template <>
DUCKDB_API bool TryCastToTimestampNS::Operation(date_t input, timestamp_t &result, bool strict);
template <>
DUCKDB_API bool TryCastToTimestampMS::Operation(date_t input, timestamp_t &result, bool strict);
template <>
DUCKDB_API bool TryCastToTimestampSec::Operation(date_t input, timestamp_t &result, bool strict);

//===--------------------------------------------------------------------===//
// Non-Standard Timestamps -> string/standard timestamp
//===--------------------------------------------------------------------===//

struct CastFromTimestampNS {
	template <class SRC>
	static inline string_t Operation(SRC input, Vector &result) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastFromTimestampMS {
	template <class SRC>
	static inline string_t Operation(SRC input, Vector &result) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastFromTimestampSec {
	template <class SRC>
	static inline string_t Operation(SRC input, Vector &result) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastTimestampUsToMs {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastTimestampUsToNs {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastTimestampUsToSec {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastTimestampMsToUs {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastTimestampNsToUs {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

struct CastTimestampSecToUs {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		throw duckdb::NotImplementedException("Cast to timestamp could not be performed!");
	}
};

template <>
duckdb::timestamp_t CastTimestampUsToMs::Operation(duckdb::timestamp_t input);
template <>
duckdb::timestamp_t CastTimestampUsToNs::Operation(duckdb::timestamp_t input);
template <>
duckdb::timestamp_t CastTimestampUsToSec::Operation(duckdb::timestamp_t input);
template <>
duckdb::timestamp_t CastTimestampMsToUs::Operation(duckdb::timestamp_t input);
template <>
duckdb::timestamp_t CastTimestampNsToUs::Operation(duckdb::timestamp_t input);
template <>
duckdb::timestamp_t CastTimestampSecToUs::Operation(duckdb::timestamp_t input);

template <>
duckdb::string_t CastFromTimestampNS::Operation(duckdb::timestamp_t input, Vector &result);
template <>
duckdb::string_t CastFromTimestampMS::Operation(duckdb::timestamp_t input, Vector &result);
template <>
duckdb::string_t CastFromTimestampSec::Operation(duckdb::timestamp_t input, Vector &result);

//===--------------------------------------------------------------------===//
// Blobs
//===--------------------------------------------------------------------===//
struct CastFromBlob {
	template <class SRC>
	static inline string_t Operation(SRC input, Vector &result) {
		throw duckdb::NotImplementedException("Cast from blob could not be performed!");
	}
};
template <>
duckdb::string_t CastFromBlob::Operation(duckdb::string_t input, Vector &vector);

struct TryCastToBlob {
	template <class SRC, class DST>
	static inline bool Operation(SRC input, DST &result, Vector &result_vector, string *error_message,
	                             bool strict = false) {
		throw InternalException("Unsupported type for try cast to blob");
	}
};

template <>
bool TryCastToBlob::Operation(string_t input, string_t &result, Vector &result_vector, string *error_message,
                              bool strict);

//===--------------------------------------------------------------------===//
// UUID
//===--------------------------------------------------------------------===//
struct CastFromUUID {
	template <class SRC>
	static inline string_t Operation(SRC input, Vector &result) {
		throw duckdb::NotImplementedException("Cast from uuid could not be performed!");
	}
};
template <>
duckdb::string_t CastFromUUID::Operation(duckdb::hugeint_t input, Vector &vector);

struct TryCastToUUID {
	template <class SRC, class DST>
	DUCKDB_API static inline bool Operation(SRC input, DST &result, Vector &result_vector, string *error_message,
	                                        bool strict = false) {
		throw InternalException("Unsupported type for try cast to uuid");
	}
};

template <>
DUCKDB_API bool TryCastToUUID::Operation(string_t input, hugeint_t &result, Vector &result_vector,
                                         string *error_message, bool strict);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/string_cast.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

//! StringCast
class Vector;

struct StringCast {
	template <class SRC>
	DUCKDB_API static inline string_t Operation(SRC input, Vector &result) {
		throw NotImplementedException("Unimplemented type for string cast!");
	}
};

template <>
DUCKDB_API duckdb::string_t StringCast::Operation(bool input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(int8_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(int16_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(int32_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(int64_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(uint8_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(uint16_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(uint32_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(uint64_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(hugeint_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(float input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(double input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(interval_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(duckdb::string_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(date_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(dtime_t input, Vector &result);
template <>
DUCKDB_API duckdb::string_t StringCast::Operation(timestamp_t input, Vector &result);

//! Temporary casting for Time Zone types. TODO: turn casting into functions.
struct StringCastTZ {
	template <typename SRC>
	static inline string_t Operation(SRC input, Vector &vector) {
		return StringCast::Operation(input, vector);
	}
};

template <>
duckdb::string_t StringCastTZ::Operation(date_t input, Vector &result);
template <>
duckdb::string_t StringCastTZ::Operation(dtime_t input, Vector &result);
template <>
duckdb::string_t StringCastTZ::Operation(timestamp_t input, Vector &result);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/numeric_cast.hpp
//
//
//===----------------------------------------------------------------------===//






#include <cmath>

namespace duckdb {

template <class SRC, class DST>
static bool TryCastWithOverflowCheck(SRC value, DST &result) {
	if (!Value::IsFinite<SRC>(value)) {
		return false;
	}
	if (NumericLimits<SRC>::IsSigned() != NumericLimits<DST>::IsSigned()) {
		if (NumericLimits<SRC>::IsSigned()) {
			// signed to unsigned conversion
			if (NumericLimits<SRC>::Digits() > NumericLimits<DST>::Digits()) {
				if (value < 0 || value > (SRC)NumericLimits<DST>::Maximum()) {
					return false;
				}
			} else {
				if (value < 0) {
					return false;
				}
			}
			result = (DST)value;
			return true;
		} else {
			// unsigned to signed conversion
			if (NumericLimits<SRC>::Digits() >= NumericLimits<DST>::Digits()) {
				if (value <= (SRC)NumericLimits<DST>::Maximum()) {
					result = (DST)value;
					return true;
				}
				return false;
			} else {
				result = (DST)value;
				return true;
			}
		}
	} else {
		// same sign conversion
		if (NumericLimits<DST>::Digits() >= NumericLimits<SRC>::Digits()) {
			result = (DST)value;
			return true;
		} else {
			if (value < SRC(NumericLimits<DST>::Minimum()) || value > SRC(NumericLimits<DST>::Maximum())) {
				return false;
			}
			result = (DST)value;
			return true;
		}
	}
}

template <class SRC, class T>
bool TryCastWithOverflowCheckFloat(SRC value, T &result, SRC min, SRC max) {
	if (!Value::IsFinite<SRC>(value)) {
		return false;
	}
	if (!(value >= min && value < max)) {
		return false;
	}
	// PG FLOAT => INT casts use statistical rounding.
	result = std::nearbyint(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(float value, int8_t &result) {
	return TryCastWithOverflowCheckFloat<float, int8_t>(value, result, -128.0f, 128.0f);
}

template <>
bool TryCastWithOverflowCheck(float value, int16_t &result) {
	return TryCastWithOverflowCheckFloat<float, int16_t>(value, result, -32768.0f, 32768.0f);
}

template <>
bool TryCastWithOverflowCheck(float value, int32_t &result) {
	return TryCastWithOverflowCheckFloat<float, int32_t>(value, result, -2147483648.0f, 2147483648.0f);
}

template <>
bool TryCastWithOverflowCheck(float value, int64_t &result) {
	return TryCastWithOverflowCheckFloat<float, int64_t>(value, result, -9223372036854775808.0f,
	                                                     9223372036854775808.0f);
}

template <>
bool TryCastWithOverflowCheck(double value, int8_t &result) {
	return TryCastWithOverflowCheckFloat<double, int8_t>(value, result, -128.0, 128.0);
}

template <>
bool TryCastWithOverflowCheck(double value, int16_t &result) {
	return TryCastWithOverflowCheckFloat<double, int16_t>(value, result, -32768.0, 32768.0);
}

template <>
bool TryCastWithOverflowCheck(double value, int32_t &result) {
	return TryCastWithOverflowCheckFloat<double, int32_t>(value, result, -2147483648.0, 2147483648.0);
}

template <>
bool TryCastWithOverflowCheck(double value, int64_t &result) {
	return TryCastWithOverflowCheckFloat<double, int64_t>(value, result, -9223372036854775808.0, 9223372036854775808.0);
}

template <>
bool TryCastWithOverflowCheck(float input, float &result) {
	result = input;
	return true;
}
template <>
bool TryCastWithOverflowCheck(float input, double &result) {
	result = double(input);
	return true;
}
template <>
bool TryCastWithOverflowCheck(double input, double &result) {
	result = input;
	return true;
}

template <>
bool TryCastWithOverflowCheck(double input, float &result) {
	if (!Value::IsFinite(input)) {
		result = float(input);
		return true;
	}
	auto res = float(input);
	if (!Value::FloatIsFinite(input)) {
		return false;
	}
	result = res;
	return true;
}

//===--------------------------------------------------------------------===//
// Cast Numeric -> bool
//===--------------------------------------------------------------------===//
template <>
bool TryCastWithOverflowCheck(bool value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(int8_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(int16_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(int32_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(int64_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(uint8_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(uint16_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(uint32_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(uint64_t value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(float value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(double value, bool &result) {
	result = bool(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(hugeint_t input, bool &result) {
	result = input.upper != 0 || input.lower != 0;
	return true;
}

//===--------------------------------------------------------------------===//
// Cast bool -> Numeric
//===--------------------------------------------------------------------===//
template <>
bool TryCastWithOverflowCheck(bool value, int8_t &result) {
	result = int8_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, int16_t &result) {
	result = int16_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, int32_t &result) {
	result = int32_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, int64_t &result) {
	result = int64_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, uint8_t &result) {
	result = uint8_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, uint16_t &result) {
	result = uint16_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, uint32_t &result) {
	result = uint32_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, uint64_t &result) {
	result = uint64_t(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, float &result) {
	result = float(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool value, double &result) {
	result = double(value);
	return true;
}

template <>
bool TryCastWithOverflowCheck(bool input, hugeint_t &result) {
	result.upper = 0;
	result.lower = input ? 1 : 0;
	return true;
}

//===--------------------------------------------------------------------===//
// Cast Numeric -> hugeint
//===--------------------------------------------------------------------===//
template <>
bool TryCastWithOverflowCheck(int8_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(int16_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(int32_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(int64_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(uint8_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(uint16_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(uint32_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(uint64_t value, hugeint_t &result) {
	return Hugeint::TryConvert(value, result);
}

template <>
bool TryCastWithOverflowCheck(float value, hugeint_t &result) {
	return Hugeint::TryConvert(std::nearbyintf(value), result);
}

template <>
bool TryCastWithOverflowCheck(double value, hugeint_t &result) {
	return Hugeint::TryConvert(std::nearbyint(value), result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, hugeint_t &result) {
	result = value;
	return true;
}

//===--------------------------------------------------------------------===//
// Cast Hugeint -> Numeric
//===--------------------------------------------------------------------===//
template <>
bool TryCastWithOverflowCheck(hugeint_t value, int8_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, int16_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, int32_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, int64_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, uint8_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, uint16_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, uint32_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, uint64_t &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, float &result) {
	return Hugeint::TryCast(value, result);
}

template <>
bool TryCastWithOverflowCheck(hugeint_t value, double &result) {
	return Hugeint::TryCast(value, result);
}

struct NumericTryCast {
	template <class SRC, class DST>
	static inline bool Operation(SRC input, DST &result, bool strict = false) {
		return TryCastWithOverflowCheck(input, result);
	}
};

struct NumericCast {
	template <class SRC, class DST>
	static inline DST Operation(SRC input) {
		DST result;
		if (!NumericTryCast::Operation(input, result)) {
			throw InvalidInputException(CastExceptionText<SRC, DST>(input));
		}
		return result;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/decimal_cast_operators.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//===--------------------------------------------------------------------===//
// Decimal Casts
//===--------------------------------------------------------------------===//
struct TryCastToDecimal {
	template <class SRC, class DST>
	DUCKDB_API static inline bool Operation(SRC input, DST &result, string *error_message, uint8_t width,
	                                        uint8_t scale) {
		throw NotImplementedException("Unimplemented type for TryCastToDecimal!");
	}
};

struct TryCastFromDecimal {
	template <class SRC, class DST>
	static inline bool Operation(SRC input, DST &result, string *error_message, uint8_t width, uint8_t scale) {
		throw NotImplementedException("Unimplemented type for TryCastFromDecimal!");
	}
};

//===--------------------------------------------------------------------===//
// Cast Decimal <-> bool
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(bool input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(bool input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(bool input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(bool input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, bool &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, bool &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, bool &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, bool &result, string *error_message, uint8_t width, uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> int8_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int8_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int8_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int8_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int8_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, int8_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, int8_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, int8_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, int8_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> int16_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int16_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int16_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int16_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int16_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, int16_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, int16_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, int16_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, int16_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> int32_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int32_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int32_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int32_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int32_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, int32_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, int32_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, int32_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, int32_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> int64_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int64_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int64_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int64_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(int64_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, int64_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, int64_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, int64_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, int64_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> hugeint_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(hugeint_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(hugeint_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(hugeint_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(hugeint_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, hugeint_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, hugeint_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, hugeint_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, hugeint_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> uint8_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint8_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint8_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint8_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint8_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, uint8_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, uint8_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, uint8_t &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, uint8_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> uint16_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint16_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint16_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint16_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint16_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, uint16_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, uint16_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, uint16_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, uint16_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> uint32_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint32_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint32_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint32_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint32_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, uint32_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, uint32_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, uint32_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, uint32_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> uint64_t
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint64_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint64_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint64_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(uint64_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, uint64_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, uint64_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, uint64_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, uint64_t &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> float
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(float input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(float input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(float input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(float input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, float &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, float &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, float &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, float &result, string *error_message, uint8_t width, uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal <-> double
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(double input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(double input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(double input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(double input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

template <>
bool TryCastFromDecimal::Operation(int16_t input, double &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int32_t input, double &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(int64_t input, double &result, string *error_message, uint8_t width, uint8_t scale);
template <>
bool TryCastFromDecimal::Operation(hugeint_t input, double &result, string *error_message, uint8_t width,
                                   uint8_t scale);

//===--------------------------------------------------------------------===//
// Cast Decimal -> VARCHAR
//===--------------------------------------------------------------------===//
template <>
DUCKDB_API bool TryCastToDecimal::Operation(string_t input, int16_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(string_t input, int32_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(string_t input, int64_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);
template <>
DUCKDB_API bool TryCastToDecimal::Operation(string_t input, hugeint_t &result, string *error_message, uint8_t width,
                                            uint8_t scale);

struct StringCastFromDecimal {
	template <class SRC>
	static inline string_t Operation(SRC input, uint8_t width, uint8_t scale, Vector &result) {
		throw NotImplementedException("Unimplemented type for string cast!");
	}
};

template <>
string_t StringCastFromDecimal::Operation(int16_t input, uint8_t width, uint8_t scale, Vector &result);
template <>
string_t StringCastFromDecimal::Operation(int32_t input, uint8_t width, uint8_t scale, Vector &result);
template <>
string_t StringCastFromDecimal::Operation(int64_t input, uint8_t width, uint8_t scale, Vector &result);
template <>
string_t StringCastFromDecimal::Operation(hugeint_t input, uint8_t width, uint8_t scale, Vector &result);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/multiply.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct MultiplyOperator {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		return left * right;
	}
};

template <>
float MultiplyOperator::Operation(float left, float right);
template <>
double MultiplyOperator::Operation(double left, double right);
template <>
interval_t MultiplyOperator::Operation(interval_t left, int64_t right);
template <>
interval_t MultiplyOperator::Operation(int64_t left, interval_t right);

struct TryMultiplyOperator {
	template <class TA, class TB, class TR>
	static inline bool Operation(TA left, TB right, TR &result) {
		throw InternalException("Unimplemented type for TryMultiplyOperator");
	}
};

template <>
bool TryMultiplyOperator::Operation(uint8_t left, uint8_t right, uint8_t &result);
template <>
bool TryMultiplyOperator::Operation(uint16_t left, uint16_t right, uint16_t &result);
template <>
bool TryMultiplyOperator::Operation(uint32_t left, uint32_t right, uint32_t &result);
template <>
bool TryMultiplyOperator::Operation(uint64_t left, uint64_t right, uint64_t &result);

template <>
bool TryMultiplyOperator::Operation(int8_t left, int8_t right, int8_t &result);
template <>
bool TryMultiplyOperator::Operation(int16_t left, int16_t right, int16_t &result);
template <>
bool TryMultiplyOperator::Operation(int32_t left, int32_t right, int32_t &result);
template <>
DUCKDB_API bool TryMultiplyOperator::Operation(int64_t left, int64_t right, int64_t &result);

struct MultiplyOperatorOverflowCheck {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		TR result;
		if (!TryMultiplyOperator::Operation(left, right, result)) {
			throw OutOfRangeException("Overflow in multiplication of %s (%d * %d)!", TypeIdToString(GetTypeId<TA>()),
			                          left, right);
		}
		return result;
	}
};

struct TryDecimalMultiply {
	template <class TA, class TB, class TR>
	static inline bool Operation(TA left, TB right, TR &result) {
		throw InternalException("Unimplemented type for TryDecimalMultiply");
	}
};

template <>
bool TryDecimalMultiply::Operation(int16_t left, int16_t right, int16_t &result);
template <>
bool TryDecimalMultiply::Operation(int32_t left, int32_t right, int32_t &result);
template <>
bool TryDecimalMultiply::Operation(int64_t left, int64_t right, int64_t &result);
template <>
bool TryDecimalMultiply::Operation(hugeint_t left, hugeint_t right, hugeint_t &result);

struct DecimalMultiplyOverflowCheck {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		TR result;
		if (!TryDecimalMultiply::Operation<TA, TB, TR>(left, right, result)) {
			throw OutOfRangeException("Overflow in multiplication of DECIMAL(18) (%d * %d). You might want to add an "
			                          "explicit cast to a bigger decimal.",
			                          left, right);
		}
		return result;
	}
};

template <>
hugeint_t DecimalMultiplyOverflowCheck::Operation(hugeint_t left, hugeint_t right);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/cast_helpers.hpp
//
//
//===----------------------------------------------------------------------===//











namespace duckdb {

//! NumericHelper is a static class that holds helper functions for integers/doubles
class NumericHelper {
public:
	static const int64_t POWERS_OF_TEN[20];
	static const double DOUBLE_POWERS_OF_TEN[40];

public:
	template <class T>
	static int UnsignedLength(T value);
	template <class SIGNED, class UNSIGNED>
	static int SignedLength(SIGNED value) {
		int sign = -(value < 0);
		UNSIGNED unsigned_value = (value ^ sign) - sign;
		return UnsignedLength(unsigned_value) - sign;
	}

	// Formats value in reverse and returns a pointer to the beginning.
	template <class T>
	static char *FormatUnsigned(T value, char *ptr) {
		while (value >= 100) {
			// Integer division is slow so do it for a group of two digits instead
			// of for every digit. The idea comes from the talk by Alexandrescu
			// "Three Optimization Tips for C++".
			auto index = static_cast<unsigned>((value % 100) * 2);
			value /= 100;
			*--ptr = duckdb_fmt::internal::data::digits[index + 1];
			*--ptr = duckdb_fmt::internal::data::digits[index];
		}
		if (value < 10) {
			*--ptr = static_cast<char>('0' + value);
			return ptr;
		}
		auto index = static_cast<unsigned>(value * 2);
		*--ptr = duckdb_fmt::internal::data::digits[index + 1];
		*--ptr = duckdb_fmt::internal::data::digits[index];
		return ptr;
	}

	template <class SIGNED, class UNSIGNED>
	static string_t FormatSigned(SIGNED value, Vector &vector) {
		int sign = -(value < 0);
		UNSIGNED unsigned_value = UNSIGNED(value ^ sign) - sign;
		int length = UnsignedLength<UNSIGNED>(unsigned_value) - sign;
		string_t result = StringVector::EmptyString(vector, length);
		auto dataptr = result.GetDataWriteable();
		auto endptr = dataptr + length;
		endptr = FormatUnsigned(unsigned_value, endptr);
		if (sign) {
			*--endptr = '-';
		}
		result.Finalize();
		return result;
	}

	template <class T>
	static std::string ToString(T value) {
		return std::to_string(value);
	}
};

template <>
int NumericHelper::UnsignedLength(uint8_t value);
template <>
int NumericHelper::UnsignedLength(uint16_t value);
template <>
int NumericHelper::UnsignedLength(uint32_t value);
template <>
int NumericHelper::UnsignedLength(uint64_t value);

template <>
std::string NumericHelper::ToString(hugeint_t value);

struct DecimalToString {
	template <class SIGNED, class UNSIGNED>
	static int DecimalLength(SIGNED value, uint8_t scale) {
		if (scale == 0) {
			// scale is 0: regular number
			return NumericHelper::SignedLength<SIGNED, UNSIGNED>(value);
		}
		// length is max of either:
		// scale + 2 OR
		// integer length + 1
		// scale + 2 happens when the number is in the range of (-1, 1)
		// in that case we print "0.XXX", which is the scale, plus "0." (2 chars)
		// integer length + 1 happens when the number is outside of that range
		// in that case we print the integer number, but with one extra character ('.')
		return MaxValue(scale + 2 + (value < 0 ? 1 : 0), NumericHelper::SignedLength<SIGNED, UNSIGNED>(value) + 1);
	}

	template <class SIGNED, class UNSIGNED>
	static void FormatDecimal(SIGNED value, uint8_t scale, char *dst, idx_t len) {
		char *end = dst + len;
		if (value < 0) {
			value = -value;
			*dst = '-';
		}
		if (scale == 0) {
			NumericHelper::FormatUnsigned<UNSIGNED>(value, end);
			return;
		}
		// we write two numbers:
		// the numbers BEFORE the decimal (major)
		// and the numbers AFTER the decimal (minor)
		UNSIGNED minor = value % (UNSIGNED)NumericHelper::POWERS_OF_TEN[scale];
		UNSIGNED major = value / (UNSIGNED)NumericHelper::POWERS_OF_TEN[scale];
		// write the number after the decimal
		dst = NumericHelper::FormatUnsigned<UNSIGNED>(minor, end);
		// (optionally) pad with zeros and add the decimal point
		while (dst > (end - scale)) {
			*--dst = '0';
		}
		*--dst = '.';
		// now write the part before the decimal
		dst = NumericHelper::FormatUnsigned<UNSIGNED>(major, dst);
	}

	template <class SIGNED, class UNSIGNED>
	static string_t Format(SIGNED value, uint8_t scale, Vector &vector) {
		int len = DecimalLength<SIGNED, UNSIGNED>(value, scale);
		string_t result = StringVector::EmptyString(vector, len);
		FormatDecimal<SIGNED, UNSIGNED>(value, scale, result.GetDataWriteable(), len);
		result.Finalize();
		return result;
	}
};

struct HugeintToStringCast {
	static int UnsignedLength(hugeint_t value) {
		D_ASSERT(value.upper >= 0);
		if (value.upper == 0) {
			return NumericHelper::UnsignedLength<uint64_t>(value.lower);
		}
		// search the length using the POWERS_OF_TEN array
		// the length has to be between [17] and [38], because the hugeint is bigger than 2^63
		// we use the same approach as above, but split a bit more because comparisons for hugeints are more expensive
		if (value >= Hugeint::POWERS_OF_TEN[27]) {
			// [27..38]
			if (value >= Hugeint::POWERS_OF_TEN[32]) {
				if (value >= Hugeint::POWERS_OF_TEN[36]) {
					int length = 37;
					length += value >= Hugeint::POWERS_OF_TEN[37];
					length += value >= Hugeint::POWERS_OF_TEN[38];
					return length;
				} else {
					int length = 33;
					length += value >= Hugeint::POWERS_OF_TEN[33];
					length += value >= Hugeint::POWERS_OF_TEN[34];
					length += value >= Hugeint::POWERS_OF_TEN[35];
					return length;
				}
			} else {
				if (value >= Hugeint::POWERS_OF_TEN[30]) {
					int length = 31;
					length += value >= Hugeint::POWERS_OF_TEN[31];
					length += value >= Hugeint::POWERS_OF_TEN[32];
					return length;
				} else {
					int length = 28;
					length += value >= Hugeint::POWERS_OF_TEN[28];
					length += value >= Hugeint::POWERS_OF_TEN[29];
					return length;
				}
			}
		} else {
			// [17..27]
			if (value >= Hugeint::POWERS_OF_TEN[22]) {
				// [22..27]
				if (value >= Hugeint::POWERS_OF_TEN[25]) {
					int length = 26;
					length += value >= Hugeint::POWERS_OF_TEN[26];
					return length;
				} else {
					int length = 23;
					length += value >= Hugeint::POWERS_OF_TEN[23];
					length += value >= Hugeint::POWERS_OF_TEN[24];
					return length;
				}
			} else {
				// [17..22]
				if (value >= Hugeint::POWERS_OF_TEN[20]) {
					int length = 21;
					length += value >= Hugeint::POWERS_OF_TEN[21];
					return length;
				} else {
					int length = 18;
					length += value >= Hugeint::POWERS_OF_TEN[18];
					length += value >= Hugeint::POWERS_OF_TEN[19];
					return length;
				}
			}
		}
	}

	// Formats value in reverse and returns a pointer to the beginning.
	static char *FormatUnsigned(hugeint_t value, char *ptr) {
		while (value.upper > 0) {
			// while integer division is slow, hugeint division is MEGA slow
			// we want to avoid doing as many divisions as possible
			// for that reason we start off doing a division by a large power of ten that uint64_t can hold
			// (100000000000000000) - this is the third largest
			// the reason we don't use the largest is because that can result in an overflow inside the division
			// function
			uint64_t remainder;
			value = Hugeint::DivModPositive(value, 100000000000000000ULL, remainder);

			auto startptr = ptr;
			// now we format the remainder: note that we need to pad with zero's in case
			// the remainder is small (i.e. less than 10000000000000000)
			ptr = NumericHelper::FormatUnsigned<uint64_t>(remainder, ptr);

			int format_length = startptr - ptr;
			// pad with zero
			for (int i = format_length; i < 17; i++) {
				*--ptr = '0';
			}
		}
		// once the value falls in the range of a uint64_t, fallback to formatting as uint64_t to avoid hugeint division
		return NumericHelper::FormatUnsigned<uint64_t>(value.lower, ptr);
	}

	static string_t FormatSigned(hugeint_t value, Vector &vector) {
		int negative = value.upper < 0;
		if (negative) {
			Hugeint::NegateInPlace(value);
		}
		int length = UnsignedLength(value) + negative;
		string_t result = StringVector::EmptyString(vector, length);
		auto dataptr = result.GetDataWriteable();
		auto endptr = dataptr + length;
		if (value.upper == 0) {
			// small value: format as uint64_t
			endptr = NumericHelper::FormatUnsigned<uint64_t>(value.lower, endptr);
		} else {
			endptr = FormatUnsigned(value, endptr);
		}
		if (negative) {
			*--endptr = '-';
		}
		D_ASSERT(endptr == dataptr);
		result.Finalize();
		return result;
	}

	static int DecimalLength(hugeint_t value, uint8_t scale) {
		int negative;
		if (value.upper < 0) {
			Hugeint::NegateInPlace(value);
			negative = 1;
		} else {
			negative = 0;
		}
		if (scale == 0) {
			// scale is 0: regular number
			return UnsignedLength(value) + negative;
		}
		// length is max of either:
		// scale + 2 OR
		// integer length + 1
		// scale + 2 happens when the number is in the range of (-1, 1)
		// in that case we print "0.XXX", which is the scale, plus "0." (2 chars)
		// integer length + 1 happens when the number is outside of that range
		// in that case we print the integer number, but with one extra character ('.')
		return MaxValue(scale + 2, UnsignedLength(value) + 1) + negative;
	}

	static void FormatDecimal(hugeint_t value, uint8_t scale, char *dst, int len) {
		auto endptr = dst + len;

		int negative = value.upper < 0;
		if (negative) {
			Hugeint::NegateInPlace(value);
			*dst = '-';
			dst++;
		}
		if (scale == 0) {
			// with scale=0 we format the number as a regular number
			FormatUnsigned(value, endptr);
			return;
		}

		// we write two numbers:
		// the numbers BEFORE the decimal (major)
		// and the numbers AFTER the decimal (minor)
		hugeint_t minor;
		hugeint_t major = Hugeint::DivMod(value, Hugeint::POWERS_OF_TEN[scale], minor);

		// write the number after the decimal
		dst = FormatUnsigned(minor, endptr);
		// (optionally) pad with zeros and add the decimal point
		while (dst > (endptr - scale)) {
			*--dst = '0';
		}
		*--dst = '.';
		// now write the part before the decimal
		dst = FormatUnsigned(major, dst);
	}

	static string_t FormatDecimal(hugeint_t value, uint8_t scale, Vector &vector) {
		int length = DecimalLength(value, scale);
		string_t result = StringVector::EmptyString(vector, length);

		auto dst = result.GetDataWriteable();

		FormatDecimal(value, scale, dst, length);

		result.Finalize();
		return result;
	}
};

struct DateToStringCast {
	static idx_t Length(int32_t date[], idx_t &year_length, bool &add_bc) {
		// format is YYYY-MM-DD with optional (BC) at the end
		// regular length is 10
		idx_t length = 6;
		year_length = 4;
		add_bc = false;
		if (date[0] <= 0) {
			// add (BC) suffix
			length += 5;
			date[0] = -date[0] + 1;
			add_bc = true;
		}

		// potentially add extra characters depending on length of year
		year_length += date[0] >= 10000;
		year_length += date[0] >= 100000;
		year_length += date[0] >= 1000000;
		year_length += date[0] >= 10000000;
		length += year_length;
		return length;
	}

	static void Format(char *data, int32_t date[], idx_t year_length, bool add_bc) {
		// now we write the string, first write the year
		auto endptr = data + year_length;
		endptr = NumericHelper::FormatUnsigned(date[0], endptr);
		// add optional leading zeros
		while (endptr > data) {
			*--endptr = '0';
		}
		// now write the month and day
		auto ptr = data + year_length;
		for (int i = 1; i <= 2; i++) {
			ptr[0] = '-';
			if (date[i] < 10) {
				ptr[1] = '0';
				ptr[2] = '0' + date[i];
			} else {
				auto index = static_cast<unsigned>(date[i] * 2);
				ptr[1] = duckdb_fmt::internal::data::digits[index];
				ptr[2] = duckdb_fmt::internal::data::digits[index + 1];
			}
			ptr += 3;
		}
		// optionally add BC to the end of the date
		if (add_bc) {
			memcpy(ptr, " (BC)", 5);
		}
	}
};

struct TimeToStringCast {
	//! Format microseconds to a buffer of length 6. Returns the number of trailing zeros
	static int32_t FormatMicros(uint32_t microseconds, char micro_buffer[]) {
		char *endptr = micro_buffer + 6;
		endptr = NumericHelper::FormatUnsigned<uint32_t>(microseconds, endptr);
		while (endptr > micro_buffer) {
			*--endptr = '0';
		}
		idx_t trailing_zeros = 0;
		for (idx_t i = 5; i > 0; i--) {
			if (micro_buffer[i] != '0') {
				break;
			}
			trailing_zeros++;
		}
		return trailing_zeros;
	}

	static idx_t Length(int32_t time[], char micro_buffer[]) {
		// format is HH:MM:DD.MS
		// microseconds come after the time with a period separator
		idx_t length;
		if (time[3] == 0) {
			// no microseconds
			// format is HH:MM:DD
			length = 8;
		} else {
			length = 15;
			// for microseconds, we truncate any trailing zeros (i.e. "90000" becomes ".9")
			// first write the microseconds to the microsecond buffer
			// we write backwards and pad with zeros to the left
			// now we figure out how many digits we need to include by looking backwards
			// and checking how many zeros we encounter
			length -= FormatMicros(time[3], micro_buffer);
		}
		return length;
	}

	static void FormatTwoDigits(char *ptr, int32_t value) {
		D_ASSERT(value >= 0 && value <= 99);
		if (value < 10) {
			ptr[0] = '0';
			ptr[1] = '0' + value;
		} else {
			auto index = static_cast<unsigned>(value * 2);
			ptr[0] = duckdb_fmt::internal::data::digits[index];
			ptr[1] = duckdb_fmt::internal::data::digits[index + 1];
		}
	}

	static void Format(char *data, idx_t length, int32_t time[], char micro_buffer[]) {
		// first write hour, month and day
		auto ptr = data;
		ptr[2] = ':';
		ptr[5] = ':';
		for (int i = 0; i <= 2; i++) {
			FormatTwoDigits(ptr, time[i]);
			ptr += 3;
		}
		if (length > 8) {
			// write the micro seconds at the end
			data[8] = '.';
			memcpy(data + 9, micro_buffer, length - 9);
		}
	}
};

struct IntervalToStringCast {
	static void FormatSignedNumber(int64_t value, char buffer[], idx_t &length) {
		int sign = -(value < 0);
		uint64_t unsigned_value = (value ^ sign) - sign;
		length += NumericHelper::UnsignedLength<uint64_t>(unsigned_value) - sign;
		auto endptr = buffer + length;
		endptr = NumericHelper::FormatUnsigned<uint64_t>(unsigned_value, endptr);
		if (sign) {
			*--endptr = '-';
		}
	}

	static void FormatTwoDigits(int64_t value, char buffer[], idx_t &length) {
		TimeToStringCast::FormatTwoDigits(buffer + length, value);
		length += 2;
	}

	static void FormatIntervalValue(int32_t value, char buffer[], idx_t &length, const char *name, idx_t name_len) {
		if (value == 0) {
			return;
		}
		if (length != 0) {
			// space if there is already something in the buffer
			buffer[length++] = ' ';
		}
		FormatSignedNumber(value, buffer, length);
		// append the name together with a potential "s" (for plurals)
		memcpy(buffer + length, name, name_len);
		length += name_len;
		if (value != 1) {
			buffer[length++] = 's';
		}
	}

	//! Formats an interval to a buffer, the buffer should be >=70 characters
	//! years: 17 characters (max value: "-2147483647 years")
	//! months: 9 (max value: "12 months")
	//! days: 16 characters (max value: "-2147483647 days")
	//! time: 24 characters (max value: -2562047788:00:00.123456)
	//! spaces between all characters (+3 characters)
	//! Total: 70 characters
	//! Returns the length of the interval
	static idx_t Format(interval_t interval, char buffer[]) {
		idx_t length = 0;
		if (interval.months != 0) {
			int32_t years = interval.months / 12;
			int32_t months = interval.months - years * 12;
			// format the years and months
			FormatIntervalValue(years, buffer, length, " year", 5);
			FormatIntervalValue(months, buffer, length, " month", 6);
		}
		if (interval.days != 0) {
			// format the days
			FormatIntervalValue(interval.days, buffer, length, " day", 4);
		}
		if (interval.micros != 0) {
			if (length != 0) {
				// space if there is already something in the buffer
				buffer[length++] = ' ';
			}
			int64_t micros = interval.micros;
			if (micros < 0) {
				// negative time: append negative sign
				buffer[length++] = '-';
				micros = -micros;
			}
			int64_t hour = micros / Interval::MICROS_PER_HOUR;
			micros -= hour * Interval::MICROS_PER_HOUR;
			int64_t min = micros / Interval::MICROS_PER_MINUTE;
			micros -= min * Interval::MICROS_PER_MINUTE;
			int64_t sec = micros / Interval::MICROS_PER_SEC;
			micros -= sec * Interval::MICROS_PER_SEC;

			if (hour < 10) {
				buffer[length++] = '0';
			}
			FormatSignedNumber(hour, buffer, length);
			buffer[length++] = ':';
			FormatTwoDigits(min, buffer, length);
			buffer[length++] = ':';
			FormatTwoDigits(sec, buffer, length);
			if (micros != 0) {
				buffer[length++] = '.';
				auto trailing_zeros = TimeToStringCast::FormatMicros(micros, buffer + length);
				length += 6 - trailing_zeros;
			}
		} else if (length == 0) {
			// empty interval: default to 00:00:00
			memcpy(buffer, "00:00:00", 8);
			return 8;
		}
		return length;
	}
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #4
// See the end of this file for a list

// duckdb_fast_float by Daniel Lemire
// duckdb_fast_float by João Paulo Magalhaes


// with contributions from Eugene Golushkov
// with contributions from Maksim Kita
// with contributions from Marcin Wojdyr
// with contributions from Neal Richardson
// with contributions from Tim Paine
// with contributions from Fabio Pellacini


// 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.


#ifndef FASTFLOAT_FAST_FLOAT_H
#define FASTFLOAT_FAST_FLOAT_H

#include <system_error>

namespace duckdb_fast_float {
enum chars_format {
    scientific = 1<<0,
    fixed = 1<<2,
    hex = 1<<3,
    general = fixed | scientific
};


struct from_chars_result {
  const char *ptr;
  std::errc ec;
};

/**
 * This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting
 * a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale.
 * The resulting floating-point value is the closest floating-point values (using either float or double),
 * using the "round to even" convention for values that would otherwise fall right in-between two values.
 * That is, we provide exact parsing according to the IEEE standard.
 *
 * Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the
 * parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned
 * `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.
 *
 * The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).
 *
 * Like the C++17 standard, the `duckdb_fast_float::from_chars` functions take an optional last argument of
 * the type `duckdb_fast_float::chars_format`. It is a bitset value: we check whether
 * `fmt & duckdb_fast_float::chars_format::fixed` and `fmt & duckdb_fast_float::chars_format::scientific` are set
 * to determine whether we allowe the fixed point and scientific notation respectively.
 * The default is  `duckdb_fast_float::chars_format::general` which allows both `fixed` and `scientific`.
 */
template<typename T>
from_chars_result from_chars(const char *first, const char *last,
                             T &value, chars_format fmt = chars_format::general)  noexcept;

}
#endif // FASTFLOAT_FAST_FLOAT_H

#ifndef FASTFLOAT_FLOAT_COMMON_H
#define FASTFLOAT_FLOAT_COMMON_H

#include <cfloat>
#include <cstdint>
#include <cassert>

#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)   \
       || defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
       || defined(__MINGW64__)                                          \
       || defined(__s390x__)                                            \
       || (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)) \
       || defined(__EMSCRIPTEN__))
#define FASTFLOAT_64BIT
#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86)   \
     || defined(__arm__) || defined(_M_ARM)                   \
     || defined(__MINGW32__))
#define FASTFLOAT_32BIT
#else
  // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.
  // We can never tell the register width, but the SIZE_MAX is a good approximation.
  // UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max portability.
  #if SIZE_MAX == 0xffff
    #error Unknown platform (16-bit, unsupported)
  #elif SIZE_MAX == 0xffffffff
    #define FASTFLOAT_32BIT
  #elif SIZE_MAX == 0xffffffffffffffff
    #define FASTFLOAT_64BIT
  #else
    #error Unknown platform (not 32-bit, not 64-bit?)
  #endif
#endif

#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__))
#include <intrin.h>
#endif

#if defined(_MSC_VER) && !defined(__clang__)
#define FASTFLOAT_VISUAL_STUDIO 1
#endif

#ifdef _WIN32
#define FASTFLOAT_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#elif defined(sun) || defined(__sun)
#include <sys/byteorder.h>
#else
#include <endian.h>
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define FASTFLOAT_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define FASTFLOAT_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define FASTFLOAT_IS_BIG_ENDIAN 0
#else
#define FASTFLOAT_IS_BIG_ENDIAN 1
#endif
#endif

#ifdef FASTFLOAT_VISUAL_STUDIO
#define fastfloat_really_inline __forceinline
#else
#define fastfloat_really_inline inline __attribute__((always_inline))
#endif

namespace duckdb_fast_float {

// Compares two ASCII strings in a case insensitive manner.
inline bool fastfloat_strncasecmp(const char *input1, const char *input2,
                                  size_t length) {
  char running_diff{0};
  for (size_t i = 0; i < length; i++) {
    running_diff |= (input1[i] ^ input2[i]);
  }
  return (running_diff == 0) || (running_diff == 32);
}

#ifndef FLT_EVAL_METHOD
#error "FLT_EVAL_METHOD should be defined, please include cfloat."
#endif

namespace {
constexpr uint32_t max_digits = 768;
constexpr uint32_t max_digit_without_overflow = 19;
constexpr int32_t decimal_point_range = 2047;
} // namespace

struct value128 {
  uint64_t low;
  uint64_t high;
  value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
  value128() : low(0), high(0) {}
};

/* result might be undefined when input_num is zero */
fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
  assert(input_num > 0);
#ifdef FASTFLOAT_VISUAL_STUDIO
  #if defined(_M_X64) || defined(_M_ARM64)
  unsigned long leading_zero = 0;
  // Search the mask data from most significant bit (MSB)
  // to least significant bit (LSB) for a set bit (1).
  _BitScanReverse64(&leading_zero, input_num);
  return (int)(63 - leading_zero);
  #else
  int last_bit = 0;
  if(input_num & uint64_t(0xffffffff00000000)) input_num >>= 32, last_bit |= 32;
  if(input_num & uint64_t(        0xffff0000)) input_num >>= 16, last_bit |= 16;
  if(input_num & uint64_t(            0xff00)) input_num >>=  8, last_bit |=  8;
  if(input_num & uint64_t(              0xf0)) input_num >>=  4, last_bit |=  4;
  if(input_num & uint64_t(               0xc)) input_num >>=  2, last_bit |=  2;
  if(input_num & uint64_t(               0x2)) input_num >>=  1, last_bit |=  1;
  return 63 - last_bit;
  #endif
#else
  return __builtin_clzll(input_num);
#endif
}

#ifdef FASTFLOAT_32BIT

// slow emulation routine for 32-bit
fastfloat_really_inline uint64_t emulu(uint32_t x, uint32_t y) {
    return x * (uint64_t)y;
}

// slow emulation routine for 32-bit
#if !defined(__MINGW64__)
fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd,
                                          uint64_t *hi) {
  uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);
  uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);
  uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));
  uint64_t adbc_carry = !!(adbc < ad);
  uint64_t lo = bd + (adbc << 32);
  *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
        (adbc_carry << 32) + !!(lo < bd);
  return lo;
}
#endif // !__MINGW64__

#endif // FASTFLOAT_32BIT


// compute 64-bit a*b
fastfloat_really_inline value128 full_multiplication(uint64_t a,
                                                     uint64_t b) {
  value128 answer;
#ifdef _M_ARM64
  // ARM64 has native support for 64-bit multiplications, no need to emulate
  answer.high = __umulh(a, b);
  answer.low = a * b;
#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__))
  answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64
#elif defined(FASTFLOAT_64BIT)
  __uint128_t r = ((__uint128_t)a) * b;
  answer.low = uint64_t(r);
  answer.high = uint64_t(r >> 64);
#else
  #error Not implemented
#endif
  return answer;
}


struct adjusted_mantissa {
  uint64_t mantissa{0};
  int power2{0}; // a negative value indicates an invalid result
  adjusted_mantissa() = default;
  bool operator==(const adjusted_mantissa &o) const {
    return mantissa == o.mantissa && power2 == o.power2;
  }
  bool operator!=(const adjusted_mantissa &o) const {
    return mantissa != o.mantissa || power2 != o.power2;
  }
};

struct decimal {
  uint32_t num_digits{0};
  int32_t decimal_point{0};
  bool negative{false};
  bool truncated{false};
  uint8_t digits[max_digits];
  decimal() = default;
  // Copies are not allowed since this is a fat object.
  decimal(const decimal &) = delete;
  // Copies are not allowed since this is a fat object.
  decimal &operator=(const decimal &) = delete;
  // Moves are allowed:
  decimal(decimal &&) = default;
  decimal &operator=(decimal &&other) = default;
};

constexpr static double powers_of_ten_double[] = {
    1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,  1e8,  1e9,  1e10, 1e11,
    1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
constexpr static float powers_of_ten_float[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5,
                                                1e6, 1e7, 1e8, 1e9, 1e10};

template <typename T> struct binary_format {
  static inline constexpr int mantissa_explicit_bits();
  static inline constexpr int minimum_exponent();
  static inline constexpr int infinite_power();
  static inline constexpr int sign_index();
  static inline constexpr int min_exponent_fast_path();
  static inline constexpr int max_exponent_fast_path();
  static inline constexpr int max_exponent_round_to_even();
  static inline constexpr int min_exponent_round_to_even();
  static inline constexpr uint64_t max_mantissa_fast_path();
  static inline constexpr int largest_power_of_ten();
  static inline constexpr int smallest_power_of_ten();
  static inline constexpr T exact_power_of_ten(int64_t power);
};

template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() {
  return 52;
}
template <> inline constexpr int binary_format<float>::mantissa_explicit_bits() {
  return 23;
}

template <> inline constexpr int binary_format<double>::max_exponent_round_to_even() {
  return 23;
}

template <> inline constexpr int binary_format<float>::max_exponent_round_to_even() {
  return 10;
}

template <> inline constexpr int binary_format<double>::min_exponent_round_to_even() {
  return -4;
}

template <> inline constexpr int binary_format<float>::min_exponent_round_to_even() {
  return -17;
}

template <> inline constexpr int binary_format<double>::minimum_exponent() {
  return -1023;
}
template <> inline constexpr int binary_format<float>::minimum_exponent() {
  return -127;
}

template <> inline constexpr int binary_format<double>::infinite_power() {
  return 0x7FF;
}
template <> inline constexpr int binary_format<float>::infinite_power() {
  return 0xFF;
}

template <> inline constexpr int binary_format<double>::sign_index() { return 63; }
template <> inline constexpr int binary_format<float>::sign_index() { return 31; }

template <> inline constexpr int binary_format<double>::min_exponent_fast_path() {
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
  return 0;
#else
  return -22;
#endif
}
template <> inline constexpr int binary_format<float>::min_exponent_fast_path() {
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
  return 0;
#else
  return -10;
#endif
}

template <> inline constexpr int binary_format<double>::max_exponent_fast_path() {
  return 22;
}
template <> inline constexpr int binary_format<float>::max_exponent_fast_path() {
  return 10;
}

template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
  return uint64_t(2) << mantissa_explicit_bits();
}
template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
  return uint64_t(2) << mantissa_explicit_bits();
}

template <>
inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) {
  return powers_of_ten_double[power];
}
template <>
inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {

  return powers_of_ten_float[power];
}


template <>
inline constexpr int binary_format<double>::largest_power_of_ten() {
  return 308;
}
template <>
inline constexpr int binary_format<float>::largest_power_of_ten() {
  return 38;
}

template <>
inline constexpr int binary_format<double>::smallest_power_of_ten() {
  return -342;
}
template <>
inline constexpr int binary_format<float>::smallest_power_of_ten() {
  return -65;
}

} // namespace duckdb_fast_float

// for convenience:
template<class OStream>
inline OStream& operator<<(OStream &out, const duckdb_fast_float::decimal &d) {
  out << "0.";
  for (size_t i = 0; i < d.num_digits; i++) {
    out << int32_t(d.digits[i]);
  }
  out << " * 10 ** " << d.decimal_point;
  return out;
}

#endif


#ifndef FASTFLOAT_ASCII_NUMBER_H
#define FASTFLOAT_ASCII_NUMBER_H

#include <cstdio>
#include <cctype>
#include <cstdint>
#include <cstring>


namespace duckdb_fast_float {

// Next function can be micro-optimized, but compilers are entirely
// able to optimize it well.
fastfloat_really_inline bool is_integer(char c)  noexcept  { return c >= '0' && c <= '9'; }

fastfloat_really_inline uint64_t byteswap(uint64_t val) {
  return (val & 0xFF00000000000000) >> 56
    | (val & 0x00FF000000000000) >> 40
    | (val & 0x0000FF0000000000) >> 24
    | (val & 0x000000FF00000000) >> 8
    | (val & 0x00000000FF000000) << 8
    | (val & 0x0000000000FF0000) << 24
    | (val & 0x000000000000FF00) << 40
    | (val & 0x00000000000000FF) << 56;
}

fastfloat_really_inline uint64_t read_u64(const char *chars) {
  uint64_t val;
  ::memcpy(&val, chars, sizeof(uint64_t));
#if FASTFLOAT_IS_BIG_ENDIAN == 1
  // Need to read as-if the number was in little-endian order.
  val = byteswap(val);
#endif
  return val;
}

fastfloat_really_inline void write_u64(uint8_t *chars, uint64_t val) {
#if FASTFLOAT_IS_BIG_ENDIAN == 1
  // Need to read as-if the number was in little-endian order.
  val = byteswap(val);
#endif
  ::memcpy(chars, &val, sizeof(uint64_t));
}

// credit  @aqrit
fastfloat_really_inline uint32_t  parse_eight_digits_unrolled(uint64_t val) {
  const uint64_t mask = 0x000000FF000000FF;
  const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
  const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
  val -= 0x3030303030303030;
  val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
  val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
  return uint32_t(val);
}

fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars)  noexcept  {
  return parse_eight_digits_unrolled(read_u64(chars));
}

// credit @aqrit
fastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val)  noexcept  {
  return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
     0x8080808080808080));
}

fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars)  noexcept  {
  return is_made_of_eight_digits_fast(read_u64(chars));
}

struct parsed_number_string {
  int64_t exponent;
  uint64_t mantissa;
  const char *lastmatch;
  bool negative;
  bool valid;
  bool too_many_digits;
};


// Assuming that you use no more than 19 digits, this will
// parse an ASCII string.
fastfloat_really_inline
parsed_number_string parse_number_string(const char *p, const char *pend, chars_format fmt) noexcept {
  parsed_number_string answer;
  answer.valid = false;
  answer.too_many_digits = false;
  answer.negative = (*p == '-');
  if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
    ++p;
    if (p == pend) {
      return answer;
    }
    if (!is_integer(*p) && (*p != '.')) { // a  sign must be followed by an integer or the dot
      return answer;
    }
  }
  const char *const start_digits = p;

  uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)

  while ((p != pend) && is_integer(*p)) {
    // a multiplication by 10 is cheaper than an arbitrary integer
    // multiplication
    i = 10 * i +
        uint64_t(*p - '0'); // might overflow, we will handle the overflow later
    ++p;
  }
  const char *const end_of_integer_part = p;
  int64_t digit_count = int64_t(end_of_integer_part - start_digits);
  int64_t exponent = 0;
  if ((p != pend) && (*p == '.')) {
    ++p;
  // Fast approach only tested under little endian systems
  if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
    i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
    p += 8;
    if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
      i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
      p += 8;
    }
  }
    while ((p != pend) && is_integer(*p)) {
      uint8_t digit = uint8_t(*p - '0');
      ++p;
      i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
    }
    exponent = end_of_integer_part + 1 - p;
    digit_count -= exponent;
  }
  // we must have encountered at least one integer!
  if (digit_count == 0) {
    return answer;
  }
  int64_t exp_number = 0;            // explicit exponential part
  if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) {
    const char * location_of_e = p;
    ++p;
    bool neg_exp = false;
    if ((p != pend) && ('-' == *p)) {
      neg_exp = true;
      ++p;
    } else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
      ++p;
    }
    if ((p == pend) || !is_integer(*p)) {
      if(!(fmt & chars_format::fixed)) {
        // We are in error.
        return answer;
      }
      // Otherwise, we will be ignoring the 'e'.
      p = location_of_e;
    } else {
      while ((p != pend) && is_integer(*p)) {
        uint8_t digit = uint8_t(*p - '0');
        if (exp_number < 0x10000) {
          exp_number = 10 * exp_number + digit;
        }
        ++p;
      }
      if(neg_exp) { exp_number = - exp_number; }
      exponent += exp_number;
    }
  } else {
    // If it scientific and not fixed, we have to bail out.
    if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }
  }
  answer.lastmatch = p;
  answer.valid = true;

  // If we frequently had to deal with long strings of digits,
  // we could extend our code by using a 128-bit integer instead
  // of a 64-bit integer. However, this is uncommon.
  //
  // We can deal with up to 19 digits.
  if (digit_count > 19) { // this is uncommon
    // It is possible that the integer had an overflow.
    // We have to handle the case where we have 0.0000somenumber.
    // We need to be mindful of the case where we only have zeroes...
    // E.g., 0.000000000...000.
    const char *start = start_digits;
    while ((start != pend) && (*start == '0' || *start == '.')) {
      if(*start == '0') { digit_count --; }
      start++;
    }
    if (digit_count > 19) {
      answer.too_many_digits = true;
      // Let us start again, this time, avoiding overflows.
      i = 0;
      p = start_digits;
      const uint64_t minimal_nineteen_digit_integer{1000000000000000000};
      while((i < minimal_nineteen_digit_integer) && (p != pend) && is_integer(*p)) {
        i = i * 10 + uint64_t(*p - '0');
        ++p;
      }
      if (i >= minimal_nineteen_digit_integer) { // We have a big integers
        exponent = end_of_integer_part - p + exp_number;
      } else { // We have a value with a fractional component.
          p++; // skip the '.'
          const char *first_after_period = p;
          while((i < minimal_nineteen_digit_integer) && (p != pend) && is_integer(*p)) {
            i = i * 10 + uint64_t(*p - '0');
            ++p;
          }
          exponent = first_after_period - p + exp_number;
      }
      // We have now corrected both exponent and i, to a truncated value
    }
  }
  answer.exponent = exponent;
  answer.mantissa = i;
  return answer;
}


// This should always succeed since it follows a call to parse_number_string
// This function could be optimized. In particular, we could stop after 19 digits
// and try to bail out. Furthermore, we should be able to recover the computed
// exponent from the pass in parse_number_string.
fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) noexcept {
  decimal answer;
  answer.num_digits = 0;
  answer.decimal_point = 0;
  answer.truncated = false;
  answer.negative = (*p == '-');
  if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
    ++p;
  }
  // skip leading zeroes
  while ((p != pend) && (*p == '0')) {
    ++p;
  }
  while ((p != pend) && is_integer(*p)) {
    if (answer.num_digits < max_digits) {
      answer.digits[answer.num_digits] = uint8_t(*p - '0');
    }
    answer.num_digits++;
    ++p;
  }
  if ((p != pend) && (*p == '.')) {
    ++p;
    const char *first_after_period = p;
    // if we have not yet encountered a zero, we have to skip it as well
    if(answer.num_digits == 0) {
      // skip zeros
      while ((p != pend) && (*p == '0')) {
       ++p;
      }
    }
    // We expect that this loop will often take the bulk of the running time
    // because when a value has lots of digits, these digits often
    while ((p + 8 <= pend) && (answer.num_digits + 8 < max_digits)) {
      uint64_t val = read_u64(p);
      if(! is_made_of_eight_digits_fast(val)) { break; }
      // We have eight digits, process them in one go!
      val -= 0x3030303030303030;
      write_u64(answer.digits + answer.num_digits, val);
      answer.num_digits += 8;
      p += 8;
    }
    while ((p != pend) && is_integer(*p)) {
      if (answer.num_digits < max_digits) {
        answer.digits[answer.num_digits] = uint8_t(*p - '0');
      }
      answer.num_digits++;
      ++p;
    }
    answer.decimal_point = int32_t(first_after_period - p);
  }
  // We want num_digits to be the number of significant digits, excluding
  // leading *and* trailing zeros! Otherwise the truncated flag later is
  // going to be misleading.
  if(answer.num_digits > 0) {
    // We potentially need the answer.num_digits > 0 guard because we
    // prune leading zeros. So with answer.num_digits > 0, we know that
    // we have at least one non-zero digit.
    const char *preverse = p - 1;
    int32_t trailing_zeros = 0;
    while ((*preverse == '0') || (*preverse == '.')) {
      if(*preverse == '0') { trailing_zeros++; };
      --preverse;
    }
    answer.decimal_point += int32_t(answer.num_digits);
    answer.num_digits -= uint32_t(trailing_zeros);
  }
  if(answer.num_digits > max_digits) {
    answer.truncated = true;
    answer.num_digits = max_digits;
  }
  if ((p != pend) && (('e' == *p) || ('E' == *p))) {
    ++p;
    bool neg_exp = false;
    if ((p != pend) && ('-' == *p)) {
      neg_exp = true;
      ++p;
    } else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
      ++p;
    }
    int32_t exp_number = 0; // exponential part
    while ((p != pend) && is_integer(*p)) {
      uint8_t digit = uint8_t(*p - '0');
      if (exp_number < 0x10000) {
        exp_number = 10 * exp_number + digit;
      }
      ++p;
    }
    answer.decimal_point += (neg_exp ? -exp_number : exp_number);
  }
  // In very rare cases, we may have fewer than 19 digits, we want to be able to reliably
  // assume that all digits up to max_digit_without_overflow have been initialized.
  for(uint32_t i = answer.num_digits; i < max_digit_without_overflow; i++) { answer.digits[i] = 0; }

  return answer;
}
} // namespace duckdb_fast_float

#endif


#ifndef FASTFLOAT_FAST_TABLE_H
#define FASTFLOAT_FAST_TABLE_H
#include <cstdint>

namespace duckdb_fast_float {

/**
 * When mapping numbers from decimal to binary,
 * we go from w * 10^q to m * 2^p but we have
 * 10^q = 5^q * 2^q, so effectively
 * we are trying to match
 * w * 2^q * 5^q to m * 2^p. Thus the powers of two
 * are not a concern since they can be represented
 * exactly using the binary notation, only the powers of five
 * affect the binary significand.
 */

/**
 * The smallest non-zero float (binary64) is 2^−1074.
 * We take as input numbers of the form w x 10^q where w < 2^64.
 * We have that w * 10^-343  <  2^(64-344) 5^-343 < 2^-1076.
 * However, we have that
 * (2^64-1) * 10^-342 =  (2^64-1) * 2^-342 * 5^-342 > 2^−1074.
 * Thus it is possible for a number of the form w * 10^-342 where
 * w is a 64-bit value to be a non-zero floating-point number.
 *********
 * Any number of form w * 10^309 where w>= 1 is going to be
 * infinite in binary64 so we never need to worry about powers
 * of 5 greater than 308.
 */
template <class unused = void>
struct powers_template {

constexpr static int smallest_power_of_five = binary_format<double>::smallest_power_of_ten();
constexpr static int largest_power_of_five = binary_format<double>::largest_power_of_ten();
constexpr static int number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1);
// Powers of five from 5^-342 all the way to 5^308 rounded toward one.
static const uint64_t power_of_five_128[number_of_entries];
};

template <class unused>
const uint64_t powers_template<unused>::power_of_five_128[number_of_entries] = {
        0xeef453d6923bd65a,0x113faa2906a13b3f,
        0x9558b4661b6565f8,0x4ac7ca59a424c507,
        0xbaaee17fa23ebf76,0x5d79bcf00d2df649,
        0xe95a99df8ace6f53,0xf4d82c2c107973dc,
        0x91d8a02bb6c10594,0x79071b9b8a4be869,
        0xb64ec836a47146f9,0x9748e2826cdee284,
        0xe3e27a444d8d98b7,0xfd1b1b2308169b25,
        0x8e6d8c6ab0787f72,0xfe30f0f5e50e20f7,
        0xb208ef855c969f4f,0xbdbd2d335e51a935,
        0xde8b2b66b3bc4723,0xad2c788035e61382,
        0x8b16fb203055ac76,0x4c3bcb5021afcc31,
        0xaddcb9e83c6b1793,0xdf4abe242a1bbf3d,
        0xd953e8624b85dd78,0xd71d6dad34a2af0d,
        0x87d4713d6f33aa6b,0x8672648c40e5ad68,
        0xa9c98d8ccb009506,0x680efdaf511f18c2,
        0xd43bf0effdc0ba48,0x212bd1b2566def2,
        0x84a57695fe98746d,0x14bb630f7604b57,
        0xa5ced43b7e3e9188,0x419ea3bd35385e2d,
        0xcf42894a5dce35ea,0x52064cac828675b9,
        0x818995ce7aa0e1b2,0x7343efebd1940993,
        0xa1ebfb4219491a1f,0x1014ebe6c5f90bf8,
        0xca66fa129f9b60a6,0xd41a26e077774ef6,
        0xfd00b897478238d0,0x8920b098955522b4,
        0x9e20735e8cb16382,0x55b46e5f5d5535b0,
        0xc5a890362fddbc62,0xeb2189f734aa831d,
        0xf712b443bbd52b7b,0xa5e9ec7501d523e4,
        0x9a6bb0aa55653b2d,0x47b233c92125366e,
        0xc1069cd4eabe89f8,0x999ec0bb696e840a,
        0xf148440a256e2c76,0xc00670ea43ca250d,
        0x96cd2a865764dbca,0x380406926a5e5728,
        0xbc807527ed3e12bc,0xc605083704f5ecf2,
        0xeba09271e88d976b,0xf7864a44c633682e,
        0x93445b8731587ea3,0x7ab3ee6afbe0211d,
        0xb8157268fdae9e4c,0x5960ea05bad82964,
        0xe61acf033d1a45df,0x6fb92487298e33bd,
        0x8fd0c16206306bab,0xa5d3b6d479f8e056,
        0xb3c4f1ba87bc8696,0x8f48a4899877186c,
        0xe0b62e2929aba83c,0x331acdabfe94de87,
        0x8c71dcd9ba0b4925,0x9ff0c08b7f1d0b14,
        0xaf8e5410288e1b6f,0x7ecf0ae5ee44dd9,
        0xdb71e91432b1a24a,0xc9e82cd9f69d6150,
        0x892731ac9faf056e,0xbe311c083a225cd2,
        0xab70fe17c79ac6ca,0x6dbd630a48aaf406,
        0xd64d3d9db981787d,0x92cbbccdad5b108,
        0x85f0468293f0eb4e,0x25bbf56008c58ea5,
        0xa76c582338ed2621,0xaf2af2b80af6f24e,
        0xd1476e2c07286faa,0x1af5af660db4aee1,
        0x82cca4db847945ca,0x50d98d9fc890ed4d,
        0xa37fce126597973c,0xe50ff107bab528a0,
        0xcc5fc196fefd7d0c,0x1e53ed49a96272c8,
        0xff77b1fcbebcdc4f,0x25e8e89c13bb0f7a,
        0x9faacf3df73609b1,0x77b191618c54e9ac,
        0xc795830d75038c1d,0xd59df5b9ef6a2417,
        0xf97ae3d0d2446f25,0x4b0573286b44ad1d,
        0x9becce62836ac577,0x4ee367f9430aec32,
        0xc2e801fb244576d5,0x229c41f793cda73f,
        0xf3a20279ed56d48a,0x6b43527578c1110f,
        0x9845418c345644d6,0x830a13896b78aaa9,
        0xbe5691ef416bd60c,0x23cc986bc656d553,
        0xedec366b11c6cb8f,0x2cbfbe86b7ec8aa8,
        0x94b3a202eb1c3f39,0x7bf7d71432f3d6a9,
        0xb9e08a83a5e34f07,0xdaf5ccd93fb0cc53,
        0xe858ad248f5c22c9,0xd1b3400f8f9cff68,
        0x91376c36d99995be,0x23100809b9c21fa1,
        0xb58547448ffffb2d,0xabd40a0c2832a78a,
        0xe2e69915b3fff9f9,0x16c90c8f323f516c,
        0x8dd01fad907ffc3b,0xae3da7d97f6792e3,
        0xb1442798f49ffb4a,0x99cd11cfdf41779c,
        0xdd95317f31c7fa1d,0x40405643d711d583,
        0x8a7d3eef7f1cfc52,0x482835ea666b2572,
        0xad1c8eab5ee43b66,0xda3243650005eecf,
        0xd863b256369d4a40,0x90bed43e40076a82,
        0x873e4f75e2224e68,0x5a7744a6e804a291,
        0xa90de3535aaae202,0x711515d0a205cb36,
        0xd3515c2831559a83,0xd5a5b44ca873e03,
        0x8412d9991ed58091,0xe858790afe9486c2,
        0xa5178fff668ae0b6,0x626e974dbe39a872,
        0xce5d73ff402d98e3,0xfb0a3d212dc8128f,
        0x80fa687f881c7f8e,0x7ce66634bc9d0b99,
        0xa139029f6a239f72,0x1c1fffc1ebc44e80,
        0xc987434744ac874e,0xa327ffb266b56220,
        0xfbe9141915d7a922,0x4bf1ff9f0062baa8,
        0x9d71ac8fada6c9b5,0x6f773fc3603db4a9,
        0xc4ce17b399107c22,0xcb550fb4384d21d3,
        0xf6019da07f549b2b,0x7e2a53a146606a48,
        0x99c102844f94e0fb,0x2eda7444cbfc426d,
        0xc0314325637a1939,0xfa911155fefb5308,
        0xf03d93eebc589f88,0x793555ab7eba27ca,
        0x96267c7535b763b5,0x4bc1558b2f3458de,
        0xbbb01b9283253ca2,0x9eb1aaedfb016f16,
        0xea9c227723ee8bcb,0x465e15a979c1cadc,
        0x92a1958a7675175f,0xbfacd89ec191ec9,
        0xb749faed14125d36,0xcef980ec671f667b,
        0xe51c79a85916f484,0x82b7e12780e7401a,
        0x8f31cc0937ae58d2,0xd1b2ecb8b0908810,
        0xb2fe3f0b8599ef07,0x861fa7e6dcb4aa15,
        0xdfbdcece67006ac9,0x67a791e093e1d49a,
        0x8bd6a141006042bd,0xe0c8bb2c5c6d24e0,
        0xaecc49914078536d,0x58fae9f773886e18,
        0xda7f5bf590966848,0xaf39a475506a899e,
        0x888f99797a5e012d,0x6d8406c952429603,
        0xaab37fd7d8f58178,0xc8e5087ba6d33b83,
        0xd5605fcdcf32e1d6,0xfb1e4a9a90880a64,
        0x855c3be0a17fcd26,0x5cf2eea09a55067f,
        0xa6b34ad8c9dfc06f,0xf42faa48c0ea481e,
        0xd0601d8efc57b08b,0xf13b94daf124da26,
        0x823c12795db6ce57,0x76c53d08d6b70858,
        0xa2cb1717b52481ed,0x54768c4b0c64ca6e,
        0xcb7ddcdda26da268,0xa9942f5dcf7dfd09,
        0xfe5d54150b090b02,0xd3f93b35435d7c4c,
        0x9efa548d26e5a6e1,0xc47bc5014a1a6daf,
        0xc6b8e9b0709f109a,0x359ab6419ca1091b,
        0xf867241c8cc6d4c0,0xc30163d203c94b62,
        0x9b407691d7fc44f8,0x79e0de63425dcf1d,
        0xc21094364dfb5636,0x985915fc12f542e4,
        0xf294b943e17a2bc4,0x3e6f5b7b17b2939d,
        0x979cf3ca6cec5b5a,0xa705992ceecf9c42,
        0xbd8430bd08277231,0x50c6ff782a838353,
        0xece53cec4a314ebd,0xa4f8bf5635246428,
        0x940f4613ae5ed136,0x871b7795e136be99,
        0xb913179899f68584,0x28e2557b59846e3f,
        0xe757dd7ec07426e5,0x331aeada2fe589cf,
        0x9096ea6f3848984f,0x3ff0d2c85def7621,
        0xb4bca50b065abe63,0xfed077a756b53a9,
        0xe1ebce4dc7f16dfb,0xd3e8495912c62894,
        0x8d3360f09cf6e4bd,0x64712dd7abbbd95c,
        0xb080392cc4349dec,0xbd8d794d96aacfb3,
        0xdca04777f541c567,0xecf0d7a0fc5583a0,
        0x89e42caaf9491b60,0xf41686c49db57244,
        0xac5d37d5b79b6239,0x311c2875c522ced5,
        0xd77485cb25823ac7,0x7d633293366b828b,
        0x86a8d39ef77164bc,0xae5dff9c02033197,
        0xa8530886b54dbdeb,0xd9f57f830283fdfc,
        0xd267caa862a12d66,0xd072df63c324fd7b,
        0x8380dea93da4bc60,0x4247cb9e59f71e6d,
        0xa46116538d0deb78,0x52d9be85f074e608,
        0xcd795be870516656,0x67902e276c921f8b,
        0x806bd9714632dff6,0xba1cd8a3db53b6,
        0xa086cfcd97bf97f3,0x80e8a40eccd228a4,
        0xc8a883c0fdaf7df0,0x6122cd128006b2cd,
        0xfad2a4b13d1b5d6c,0x796b805720085f81,
        0x9cc3a6eec6311a63,0xcbe3303674053bb0,
        0xc3f490aa77bd60fc,0xbedbfc4411068a9c,
        0xf4f1b4d515acb93b,0xee92fb5515482d44,
        0x991711052d8bf3c5,0x751bdd152d4d1c4a,
        0xbf5cd54678eef0b6,0xd262d45a78a0635d,
        0xef340a98172aace4,0x86fb897116c87c34,
        0x9580869f0e7aac0e,0xd45d35e6ae3d4da0,
        0xbae0a846d2195712,0x8974836059cca109,
        0xe998d258869facd7,0x2bd1a438703fc94b,
        0x91ff83775423cc06,0x7b6306a34627ddcf,
        0xb67f6455292cbf08,0x1a3bc84c17b1d542,
        0xe41f3d6a7377eeca,0x20caba5f1d9e4a93,
        0x8e938662882af53e,0x547eb47b7282ee9c,
        0xb23867fb2a35b28d,0xe99e619a4f23aa43,
        0xdec681f9f4c31f31,0x6405fa00e2ec94d4,
        0x8b3c113c38f9f37e,0xde83bc408dd3dd04,
        0xae0b158b4738705e,0x9624ab50b148d445,
        0xd98ddaee19068c76,0x3badd624dd9b0957,
        0x87f8a8d4cfa417c9,0xe54ca5d70a80e5d6,
        0xa9f6d30a038d1dbc,0x5e9fcf4ccd211f4c,
        0xd47487cc8470652b,0x7647c3200069671f,
        0x84c8d4dfd2c63f3b,0x29ecd9f40041e073,
        0xa5fb0a17c777cf09,0xf468107100525890,
        0xcf79cc9db955c2cc,0x7182148d4066eeb4,
        0x81ac1fe293d599bf,0xc6f14cd848405530,
        0xa21727db38cb002f,0xb8ada00e5a506a7c,
        0xca9cf1d206fdc03b,0xa6d90811f0e4851c,
        0xfd442e4688bd304a,0x908f4a166d1da663,
        0x9e4a9cec15763e2e,0x9a598e4e043287fe,
        0xc5dd44271ad3cdba,0x40eff1e1853f29fd,
        0xf7549530e188c128,0xd12bee59e68ef47c,
        0x9a94dd3e8cf578b9,0x82bb74f8301958ce,
        0xc13a148e3032d6e7,0xe36a52363c1faf01,
        0xf18899b1bc3f8ca1,0xdc44e6c3cb279ac1,
        0x96f5600f15a7b7e5,0x29ab103a5ef8c0b9,
        0xbcb2b812db11a5de,0x7415d448f6b6f0e7,
        0xebdf661791d60f56,0x111b495b3464ad21,
        0x936b9fcebb25c995,0xcab10dd900beec34,
        0xb84687c269ef3bfb,0x3d5d514f40eea742,
        0xe65829b3046b0afa,0xcb4a5a3112a5112,
        0x8ff71a0fe2c2e6dc,0x47f0e785eaba72ab,
        0xb3f4e093db73a093,0x59ed216765690f56,
        0xe0f218b8d25088b8,0x306869c13ec3532c,
        0x8c974f7383725573,0x1e414218c73a13fb,
        0xafbd2350644eeacf,0xe5d1929ef90898fa,
        0xdbac6c247d62a583,0xdf45f746b74abf39,
        0x894bc396ce5da772,0x6b8bba8c328eb783,
        0xab9eb47c81f5114f,0x66ea92f3f326564,
        0xd686619ba27255a2,0xc80a537b0efefebd,
        0x8613fd0145877585,0xbd06742ce95f5f36,
        0xa798fc4196e952e7,0x2c48113823b73704,
        0xd17f3b51fca3a7a0,0xf75a15862ca504c5,
        0x82ef85133de648c4,0x9a984d73dbe722fb,
        0xa3ab66580d5fdaf5,0xc13e60d0d2e0ebba,
        0xcc963fee10b7d1b3,0x318df905079926a8,
        0xffbbcfe994e5c61f,0xfdf17746497f7052,
        0x9fd561f1fd0f9bd3,0xfeb6ea8bedefa633,
        0xc7caba6e7c5382c8,0xfe64a52ee96b8fc0,
        0xf9bd690a1b68637b,0x3dfdce7aa3c673b0,
        0x9c1661a651213e2d,0x6bea10ca65c084e,
        0xc31bfa0fe5698db8,0x486e494fcff30a62,
        0xf3e2f893dec3f126,0x5a89dba3c3efccfa,
        0x986ddb5c6b3a76b7,0xf89629465a75e01c,
        0xbe89523386091465,0xf6bbb397f1135823,
        0xee2ba6c0678b597f,0x746aa07ded582e2c,
        0x94db483840b717ef,0xa8c2a44eb4571cdc,
        0xba121a4650e4ddeb,0x92f34d62616ce413,
        0xe896a0d7e51e1566,0x77b020baf9c81d17,
        0x915e2486ef32cd60,0xace1474dc1d122e,
        0xb5b5ada8aaff80b8,0xd819992132456ba,
        0xe3231912d5bf60e6,0x10e1fff697ed6c69,
        0x8df5efabc5979c8f,0xca8d3ffa1ef463c1,
        0xb1736b96b6fd83b3,0xbd308ff8a6b17cb2,
        0xddd0467c64bce4a0,0xac7cb3f6d05ddbde,
        0x8aa22c0dbef60ee4,0x6bcdf07a423aa96b,
        0xad4ab7112eb3929d,0x86c16c98d2c953c6,
        0xd89d64d57a607744,0xe871c7bf077ba8b7,
        0x87625f056c7c4a8b,0x11471cd764ad4972,
        0xa93af6c6c79b5d2d,0xd598e40d3dd89bcf,
        0xd389b47879823479,0x4aff1d108d4ec2c3,
        0x843610cb4bf160cb,0xcedf722a585139ba,
        0xa54394fe1eedb8fe,0xc2974eb4ee658828,
        0xce947a3da6a9273e,0x733d226229feea32,
        0x811ccc668829b887,0x806357d5a3f525f,
        0xa163ff802a3426a8,0xca07c2dcb0cf26f7,
        0xc9bcff6034c13052,0xfc89b393dd02f0b5,
        0xfc2c3f3841f17c67,0xbbac2078d443ace2,
        0x9d9ba7832936edc0,0xd54b944b84aa4c0d,
        0xc5029163f384a931,0xa9e795e65d4df11,
        0xf64335bcf065d37d,0x4d4617b5ff4a16d5,
        0x99ea0196163fa42e,0x504bced1bf8e4e45,
        0xc06481fb9bcf8d39,0xe45ec2862f71e1d6,
        0xf07da27a82c37088,0x5d767327bb4e5a4c,
        0x964e858c91ba2655,0x3a6a07f8d510f86f,
        0xbbe226efb628afea,0x890489f70a55368b,
        0xeadab0aba3b2dbe5,0x2b45ac74ccea842e,
        0x92c8ae6b464fc96f,0x3b0b8bc90012929d,
        0xb77ada0617e3bbcb,0x9ce6ebb40173744,
        0xe55990879ddcaabd,0xcc420a6a101d0515,
        0x8f57fa54c2a9eab6,0x9fa946824a12232d,
        0xb32df8e9f3546564,0x47939822dc96abf9,
        0xdff9772470297ebd,0x59787e2b93bc56f7,
        0x8bfbea76c619ef36,0x57eb4edb3c55b65a,
        0xaefae51477a06b03,0xede622920b6b23f1,
        0xdab99e59958885c4,0xe95fab368e45eced,
        0x88b402f7fd75539b,0x11dbcb0218ebb414,
        0xaae103b5fcd2a881,0xd652bdc29f26a119,
        0xd59944a37c0752a2,0x4be76d3346f0495f,
        0x857fcae62d8493a5,0x6f70a4400c562ddb,
        0xa6dfbd9fb8e5b88e,0xcb4ccd500f6bb952,
        0xd097ad07a71f26b2,0x7e2000a41346a7a7,
        0x825ecc24c873782f,0x8ed400668c0c28c8,
        0xa2f67f2dfa90563b,0x728900802f0f32fa,
        0xcbb41ef979346bca,0x4f2b40a03ad2ffb9,
        0xfea126b7d78186bc,0xe2f610c84987bfa8,
        0x9f24b832e6b0f436,0xdd9ca7d2df4d7c9,
        0xc6ede63fa05d3143,0x91503d1c79720dbb,
        0xf8a95fcf88747d94,0x75a44c6397ce912a,
        0x9b69dbe1b548ce7c,0xc986afbe3ee11aba,
        0xc24452da229b021b,0xfbe85badce996168,
        0xf2d56790ab41c2a2,0xfae27299423fb9c3,
        0x97c560ba6b0919a5,0xdccd879fc967d41a,
        0xbdb6b8e905cb600f,0x5400e987bbc1c920,
        0xed246723473e3813,0x290123e9aab23b68,
        0x9436c0760c86e30b,0xf9a0b6720aaf6521,
        0xb94470938fa89bce,0xf808e40e8d5b3e69,
        0xe7958cb87392c2c2,0xb60b1d1230b20e04,
        0x90bd77f3483bb9b9,0xb1c6f22b5e6f48c2,
        0xb4ecd5f01a4aa828,0x1e38aeb6360b1af3,
        0xe2280b6c20dd5232,0x25c6da63c38de1b0,
        0x8d590723948a535f,0x579c487e5a38ad0e,
        0xb0af48ec79ace837,0x2d835a9df0c6d851,
        0xdcdb1b2798182244,0xf8e431456cf88e65,
        0x8a08f0f8bf0f156b,0x1b8e9ecb641b58ff,
        0xac8b2d36eed2dac5,0xe272467e3d222f3f,
        0xd7adf884aa879177,0x5b0ed81dcc6abb0f,
        0x86ccbb52ea94baea,0x98e947129fc2b4e9,
        0xa87fea27a539e9a5,0x3f2398d747b36224,
        0xd29fe4b18e88640e,0x8eec7f0d19a03aad,
        0x83a3eeeef9153e89,0x1953cf68300424ac,
        0xa48ceaaab75a8e2b,0x5fa8c3423c052dd7,
        0xcdb02555653131b6,0x3792f412cb06794d,
        0x808e17555f3ebf11,0xe2bbd88bbee40bd0,
        0xa0b19d2ab70e6ed6,0x5b6aceaeae9d0ec4,
        0xc8de047564d20a8b,0xf245825a5a445275,
        0xfb158592be068d2e,0xeed6e2f0f0d56712,
        0x9ced737bb6c4183d,0x55464dd69685606b,
        0xc428d05aa4751e4c,0xaa97e14c3c26b886,
        0xf53304714d9265df,0xd53dd99f4b3066a8,
        0x993fe2c6d07b7fab,0xe546a8038efe4029,
        0xbf8fdb78849a5f96,0xde98520472bdd033,
        0xef73d256a5c0f77c,0x963e66858f6d4440,
        0x95a8637627989aad,0xdde7001379a44aa8,
        0xbb127c53b17ec159,0x5560c018580d5d52,
        0xe9d71b689dde71af,0xaab8f01e6e10b4a6,
        0x9226712162ab070d,0xcab3961304ca70e8,
        0xb6b00d69bb55c8d1,0x3d607b97c5fd0d22,
        0xe45c10c42a2b3b05,0x8cb89a7db77c506a,
        0x8eb98a7a9a5b04e3,0x77f3608e92adb242,
        0xb267ed1940f1c61c,0x55f038b237591ed3,
        0xdf01e85f912e37a3,0x6b6c46dec52f6688,
        0x8b61313bbabce2c6,0x2323ac4b3b3da015,
        0xae397d8aa96c1b77,0xabec975e0a0d081a,
        0xd9c7dced53c72255,0x96e7bd358c904a21,
        0x881cea14545c7575,0x7e50d64177da2e54,
        0xaa242499697392d2,0xdde50bd1d5d0b9e9,
        0xd4ad2dbfc3d07787,0x955e4ec64b44e864,
        0x84ec3c97da624ab4,0xbd5af13bef0b113e,
        0xa6274bbdd0fadd61,0xecb1ad8aeacdd58e,
        0xcfb11ead453994ba,0x67de18eda5814af2,
        0x81ceb32c4b43fcf4,0x80eacf948770ced7,
        0xa2425ff75e14fc31,0xa1258379a94d028d,
        0xcad2f7f5359a3b3e,0x96ee45813a04330,
        0xfd87b5f28300ca0d,0x8bca9d6e188853fc,
        0x9e74d1b791e07e48,0x775ea264cf55347e,
        0xc612062576589dda,0x95364afe032a819e,
        0xf79687aed3eec551,0x3a83ddbd83f52205,
        0x9abe14cd44753b52,0xc4926a9672793543,
        0xc16d9a0095928a27,0x75b7053c0f178294,
        0xf1c90080baf72cb1,0x5324c68b12dd6339,
        0x971da05074da7bee,0xd3f6fc16ebca5e04,
        0xbce5086492111aea,0x88f4bb1ca6bcf585,
        0xec1e4a7db69561a5,0x2b31e9e3d06c32e6,
        0x9392ee8e921d5d07,0x3aff322e62439fd0,
        0xb877aa3236a4b449,0x9befeb9fad487c3,
        0xe69594bec44de15b,0x4c2ebe687989a9b4,
        0x901d7cf73ab0acd9,0xf9d37014bf60a11,
        0xb424dc35095cd80f,0x538484c19ef38c95,
        0xe12e13424bb40e13,0x2865a5f206b06fba,
        0x8cbccc096f5088cb,0xf93f87b7442e45d4,
        0xafebff0bcb24aafe,0xf78f69a51539d749,
        0xdbe6fecebdedd5be,0xb573440e5a884d1c,
        0x89705f4136b4a597,0x31680a88f8953031,
        0xabcc77118461cefc,0xfdc20d2b36ba7c3e,
        0xd6bf94d5e57a42bc,0x3d32907604691b4d,
        0x8637bd05af6c69b5,0xa63f9a49c2c1b110,
        0xa7c5ac471b478423,0xfcf80dc33721d54,
        0xd1b71758e219652b,0xd3c36113404ea4a9,
        0x83126e978d4fdf3b,0x645a1cac083126ea,
        0xa3d70a3d70a3d70a,0x3d70a3d70a3d70a4,
        0xcccccccccccccccc,0xcccccccccccccccd,
        0x8000000000000000,0x0,
        0xa000000000000000,0x0,
        0xc800000000000000,0x0,
        0xfa00000000000000,0x0,
        0x9c40000000000000,0x0,
        0xc350000000000000,0x0,
        0xf424000000000000,0x0,
        0x9896800000000000,0x0,
        0xbebc200000000000,0x0,
        0xee6b280000000000,0x0,
        0x9502f90000000000,0x0,
        0xba43b74000000000,0x0,
        0xe8d4a51000000000,0x0,
        0x9184e72a00000000,0x0,
        0xb5e620f480000000,0x0,
        0xe35fa931a0000000,0x0,
        0x8e1bc9bf04000000,0x0,
        0xb1a2bc2ec5000000,0x0,
        0xde0b6b3a76400000,0x0,
        0x8ac7230489e80000,0x0,
        0xad78ebc5ac620000,0x0,
        0xd8d726b7177a8000,0x0,
        0x878678326eac9000,0x0,
        0xa968163f0a57b400,0x0,
        0xd3c21bcecceda100,0x0,
        0x84595161401484a0,0x0,
        0xa56fa5b99019a5c8,0x0,
        0xcecb8f27f4200f3a,0x0,
        0x813f3978f8940984,0x4000000000000000,
        0xa18f07d736b90be5,0x5000000000000000,
        0xc9f2c9cd04674ede,0xa400000000000000,
        0xfc6f7c4045812296,0x4d00000000000000,
        0x9dc5ada82b70b59d,0xf020000000000000,
        0xc5371912364ce305,0x6c28000000000000,
        0xf684df56c3e01bc6,0xc732000000000000,
        0x9a130b963a6c115c,0x3c7f400000000000,
        0xc097ce7bc90715b3,0x4b9f100000000000,
        0xf0bdc21abb48db20,0x1e86d40000000000,
        0x96769950b50d88f4,0x1314448000000000,
        0xbc143fa4e250eb31,0x17d955a000000000,
        0xeb194f8e1ae525fd,0x5dcfab0800000000,
        0x92efd1b8d0cf37be,0x5aa1cae500000000,
        0xb7abc627050305ad,0xf14a3d9e40000000,
        0xe596b7b0c643c719,0x6d9ccd05d0000000,
        0x8f7e32ce7bea5c6f,0xe4820023a2000000,
        0xb35dbf821ae4f38b,0xdda2802c8a800000,
        0xe0352f62a19e306e,0xd50b2037ad200000,
        0x8c213d9da502de45,0x4526f422cc340000,
        0xaf298d050e4395d6,0x9670b12b7f410000,
        0xdaf3f04651d47b4c,0x3c0cdd765f114000,
        0x88d8762bf324cd0f,0xa5880a69fb6ac800,
        0xab0e93b6efee0053,0x8eea0d047a457a00,
        0xd5d238a4abe98068,0x72a4904598d6d880,
        0x85a36366eb71f041,0x47a6da2b7f864750,
        0xa70c3c40a64e6c51,0x999090b65f67d924,
        0xd0cf4b50cfe20765,0xfff4b4e3f741cf6d,
        0x82818f1281ed449f,0xbff8f10e7a8921a4,
        0xa321f2d7226895c7,0xaff72d52192b6a0d,
        0xcbea6f8ceb02bb39,0x9bf4f8a69f764490,
        0xfee50b7025c36a08,0x2f236d04753d5b4,
        0x9f4f2726179a2245,0x1d762422c946590,
        0xc722f0ef9d80aad6,0x424d3ad2b7b97ef5,
        0xf8ebad2b84e0d58b,0xd2e0898765a7deb2,
        0x9b934c3b330c8577,0x63cc55f49f88eb2f,
        0xc2781f49ffcfa6d5,0x3cbf6b71c76b25fb,
        0xf316271c7fc3908a,0x8bef464e3945ef7a,
        0x97edd871cfda3a56,0x97758bf0e3cbb5ac,
        0xbde94e8e43d0c8ec,0x3d52eeed1cbea317,
        0xed63a231d4c4fb27,0x4ca7aaa863ee4bdd,
        0x945e455f24fb1cf8,0x8fe8caa93e74ef6a,
        0xb975d6b6ee39e436,0xb3e2fd538e122b44,
        0xe7d34c64a9c85d44,0x60dbbca87196b616,
        0x90e40fbeea1d3a4a,0xbc8955e946fe31cd,
        0xb51d13aea4a488dd,0x6babab6398bdbe41,
        0xe264589a4dcdab14,0xc696963c7eed2dd1,
        0x8d7eb76070a08aec,0xfc1e1de5cf543ca2,
        0xb0de65388cc8ada8,0x3b25a55f43294bcb,
        0xdd15fe86affad912,0x49ef0eb713f39ebe,
        0x8a2dbf142dfcc7ab,0x6e3569326c784337,
        0xacb92ed9397bf996,0x49c2c37f07965404,
        0xd7e77a8f87daf7fb,0xdc33745ec97be906,
        0x86f0ac99b4e8dafd,0x69a028bb3ded71a3,
        0xa8acd7c0222311bc,0xc40832ea0d68ce0c,
        0xd2d80db02aabd62b,0xf50a3fa490c30190,
        0x83c7088e1aab65db,0x792667c6da79e0fa,
        0xa4b8cab1a1563f52,0x577001b891185938,
        0xcde6fd5e09abcf26,0xed4c0226b55e6f86,
        0x80b05e5ac60b6178,0x544f8158315b05b4,
        0xa0dc75f1778e39d6,0x696361ae3db1c721,
        0xc913936dd571c84c,0x3bc3a19cd1e38e9,
        0xfb5878494ace3a5f,0x4ab48a04065c723,
        0x9d174b2dcec0e47b,0x62eb0d64283f9c76,
        0xc45d1df942711d9a,0x3ba5d0bd324f8394,
        0xf5746577930d6500,0xca8f44ec7ee36479,
        0x9968bf6abbe85f20,0x7e998b13cf4e1ecb,
        0xbfc2ef456ae276e8,0x9e3fedd8c321a67e,
        0xefb3ab16c59b14a2,0xc5cfe94ef3ea101e,
        0x95d04aee3b80ece5,0xbba1f1d158724a12,
        0xbb445da9ca61281f,0x2a8a6e45ae8edc97,
        0xea1575143cf97226,0xf52d09d71a3293bd,
        0x924d692ca61be758,0x593c2626705f9c56,
        0xb6e0c377cfa2e12e,0x6f8b2fb00c77836c,
        0xe498f455c38b997a,0xb6dfb9c0f956447,
        0x8edf98b59a373fec,0x4724bd4189bd5eac,
        0xb2977ee300c50fe7,0x58edec91ec2cb657,
        0xdf3d5e9bc0f653e1,0x2f2967b66737e3ed,
        0x8b865b215899f46c,0xbd79e0d20082ee74,
        0xae67f1e9aec07187,0xecd8590680a3aa11,
        0xda01ee641a708de9,0xe80e6f4820cc9495,
        0x884134fe908658b2,0x3109058d147fdcdd,
        0xaa51823e34a7eede,0xbd4b46f0599fd415,
        0xd4e5e2cdc1d1ea96,0x6c9e18ac7007c91a,
        0x850fadc09923329e,0x3e2cf6bc604ddb0,
        0xa6539930bf6bff45,0x84db8346b786151c,
        0xcfe87f7cef46ff16,0xe612641865679a63,
        0x81f14fae158c5f6e,0x4fcb7e8f3f60c07e,
        0xa26da3999aef7749,0xe3be5e330f38f09d,
        0xcb090c8001ab551c,0x5cadf5bfd3072cc5,
        0xfdcb4fa002162a63,0x73d9732fc7c8f7f6,
        0x9e9f11c4014dda7e,0x2867e7fddcdd9afa,
        0xc646d63501a1511d,0xb281e1fd541501b8,
        0xf7d88bc24209a565,0x1f225a7ca91a4226,
        0x9ae757596946075f,0x3375788de9b06958,
        0xc1a12d2fc3978937,0x52d6b1641c83ae,
        0xf209787bb47d6b84,0xc0678c5dbd23a49a,
        0x9745eb4d50ce6332,0xf840b7ba963646e0,
        0xbd176620a501fbff,0xb650e5a93bc3d898,
        0xec5d3fa8ce427aff,0xa3e51f138ab4cebe,
        0x93ba47c980e98cdf,0xc66f336c36b10137,
        0xb8a8d9bbe123f017,0xb80b0047445d4184,
        0xe6d3102ad96cec1d,0xa60dc059157491e5,
        0x9043ea1ac7e41392,0x87c89837ad68db2f,
        0xb454e4a179dd1877,0x29babe4598c311fb,
        0xe16a1dc9d8545e94,0xf4296dd6fef3d67a,
        0x8ce2529e2734bb1d,0x1899e4a65f58660c,
        0xb01ae745b101e9e4,0x5ec05dcff72e7f8f,
        0xdc21a1171d42645d,0x76707543f4fa1f73,
        0x899504ae72497eba,0x6a06494a791c53a8,
        0xabfa45da0edbde69,0x487db9d17636892,
        0xd6f8d7509292d603,0x45a9d2845d3c42b6,
        0x865b86925b9bc5c2,0xb8a2392ba45a9b2,
        0xa7f26836f282b732,0x8e6cac7768d7141e,
        0xd1ef0244af2364ff,0x3207d795430cd926,
        0x8335616aed761f1f,0x7f44e6bd49e807b8,
        0xa402b9c5a8d3a6e7,0x5f16206c9c6209a6,
        0xcd036837130890a1,0x36dba887c37a8c0f,
        0x802221226be55a64,0xc2494954da2c9789,
        0xa02aa96b06deb0fd,0xf2db9baa10b7bd6c,
        0xc83553c5c8965d3d,0x6f92829494e5acc7,
        0xfa42a8b73abbf48c,0xcb772339ba1f17f9,
        0x9c69a97284b578d7,0xff2a760414536efb,
        0xc38413cf25e2d70d,0xfef5138519684aba,
        0xf46518c2ef5b8cd1,0x7eb258665fc25d69,
        0x98bf2f79d5993802,0xef2f773ffbd97a61,
        0xbeeefb584aff8603,0xaafb550ffacfd8fa,
        0xeeaaba2e5dbf6784,0x95ba2a53f983cf38,
        0x952ab45cfa97a0b2,0xdd945a747bf26183,
        0xba756174393d88df,0x94f971119aeef9e4,
        0xe912b9d1478ceb17,0x7a37cd5601aab85d,
        0x91abb422ccb812ee,0xac62e055c10ab33a,
        0xb616a12b7fe617aa,0x577b986b314d6009,
        0xe39c49765fdf9d94,0xed5a7e85fda0b80b,
        0x8e41ade9fbebc27d,0x14588f13be847307,
        0xb1d219647ae6b31c,0x596eb2d8ae258fc8,
        0xde469fbd99a05fe3,0x6fca5f8ed9aef3bb,
        0x8aec23d680043bee,0x25de7bb9480d5854,
        0xada72ccc20054ae9,0xaf561aa79a10ae6a,
        0xd910f7ff28069da4,0x1b2ba1518094da04,
        0x87aa9aff79042286,0x90fb44d2f05d0842,
        0xa99541bf57452b28,0x353a1607ac744a53,
        0xd3fa922f2d1675f2,0x42889b8997915ce8,
        0x847c9b5d7c2e09b7,0x69956135febada11,
        0xa59bc234db398c25,0x43fab9837e699095,
        0xcf02b2c21207ef2e,0x94f967e45e03f4bb,
        0x8161afb94b44f57d,0x1d1be0eebac278f5,
        0xa1ba1ba79e1632dc,0x6462d92a69731732,
        0xca28a291859bbf93,0x7d7b8f7503cfdcfe,
        0xfcb2cb35e702af78,0x5cda735244c3d43e,
        0x9defbf01b061adab,0x3a0888136afa64a7,
        0xc56baec21c7a1916,0x88aaa1845b8fdd0,
        0xf6c69a72a3989f5b,0x8aad549e57273d45,
        0x9a3c2087a63f6399,0x36ac54e2f678864b,
        0xc0cb28a98fcf3c7f,0x84576a1bb416a7dd,
        0xf0fdf2d3f3c30b9f,0x656d44a2a11c51d5,
        0x969eb7c47859e743,0x9f644ae5a4b1b325,
        0xbc4665b596706114,0x873d5d9f0dde1fee,
        0xeb57ff22fc0c7959,0xa90cb506d155a7ea,
        0x9316ff75dd87cbd8,0x9a7f12442d588f2,
        0xb7dcbf5354e9bece,0xc11ed6d538aeb2f,
        0xe5d3ef282a242e81,0x8f1668c8a86da5fa,
        0x8fa475791a569d10,0xf96e017d694487bc,
        0xb38d92d760ec4455,0x37c981dcc395a9ac,
        0xe070f78d3927556a,0x85bbe253f47b1417,
        0x8c469ab843b89562,0x93956d7478ccec8e,
        0xaf58416654a6babb,0x387ac8d1970027b2,
        0xdb2e51bfe9d0696a,0x6997b05fcc0319e,
        0x88fcf317f22241e2,0x441fece3bdf81f03,
        0xab3c2fddeeaad25a,0xd527e81cad7626c3,
        0xd60b3bd56a5586f1,0x8a71e223d8d3b074,
        0x85c7056562757456,0xf6872d5667844e49,
        0xa738c6bebb12d16c,0xb428f8ac016561db,
        0xd106f86e69d785c7,0xe13336d701beba52,
        0x82a45b450226b39c,0xecc0024661173473,
        0xa34d721642b06084,0x27f002d7f95d0190,
        0xcc20ce9bd35c78a5,0x31ec038df7b441f4,
        0xff290242c83396ce,0x7e67047175a15271,
        0x9f79a169bd203e41,0xf0062c6e984d386,
        0xc75809c42c684dd1,0x52c07b78a3e60868,
        0xf92e0c3537826145,0xa7709a56ccdf8a82,
        0x9bbcc7a142b17ccb,0x88a66076400bb691,
        0xc2abf989935ddbfe,0x6acff893d00ea435,
        0xf356f7ebf83552fe,0x583f6b8c4124d43,
        0x98165af37b2153de,0xc3727a337a8b704a,
        0xbe1bf1b059e9a8d6,0x744f18c0592e4c5c,
        0xeda2ee1c7064130c,0x1162def06f79df73,
        0x9485d4d1c63e8be7,0x8addcb5645ac2ba8,
        0xb9a74a0637ce2ee1,0x6d953e2bd7173692,
        0xe8111c87c5c1ba99,0xc8fa8db6ccdd0437,
        0x910ab1d4db9914a0,0x1d9c9892400a22a2,
        0xb54d5e4a127f59c8,0x2503beb6d00cab4b,
        0xe2a0b5dc971f303a,0x2e44ae64840fd61d,
        0x8da471a9de737e24,0x5ceaecfed289e5d2,
        0xb10d8e1456105dad,0x7425a83e872c5f47,
        0xdd50f1996b947518,0xd12f124e28f77719,
        0x8a5296ffe33cc92f,0x82bd6b70d99aaa6f,
        0xace73cbfdc0bfb7b,0x636cc64d1001550b,
        0xd8210befd30efa5a,0x3c47f7e05401aa4e,
        0x8714a775e3e95c78,0x65acfaec34810a71,
        0xa8d9d1535ce3b396,0x7f1839a741a14d0d,
        0xd31045a8341ca07c,0x1ede48111209a050,
        0x83ea2b892091e44d,0x934aed0aab460432,
        0xa4e4b66b68b65d60,0xf81da84d5617853f,
        0xce1de40642e3f4b9,0x36251260ab9d668e,
        0x80d2ae83e9ce78f3,0xc1d72b7c6b426019,
        0xa1075a24e4421730,0xb24cf65b8612f81f,
        0xc94930ae1d529cfc,0xdee033f26797b627,
        0xfb9b7cd9a4a7443c,0x169840ef017da3b1,
        0x9d412e0806e88aa5,0x8e1f289560ee864e,
        0xc491798a08a2ad4e,0xf1a6f2bab92a27e2,
        0xf5b5d7ec8acb58a2,0xae10af696774b1db,
        0x9991a6f3d6bf1765,0xacca6da1e0a8ef29,
        0xbff610b0cc6edd3f,0x17fd090a58d32af3,
        0xeff394dcff8a948e,0xddfc4b4cef07f5b0,
        0x95f83d0a1fb69cd9,0x4abdaf101564f98e,
        0xbb764c4ca7a4440f,0x9d6d1ad41abe37f1,
        0xea53df5fd18d5513,0x84c86189216dc5ed,
        0x92746b9be2f8552c,0x32fd3cf5b4e49bb4,
        0xb7118682dbb66a77,0x3fbc8c33221dc2a1,
        0xe4d5e82392a40515,0xfabaf3feaa5334a,
        0x8f05b1163ba6832d,0x29cb4d87f2a7400e,
        0xb2c71d5bca9023f8,0x743e20e9ef511012,
        0xdf78e4b2bd342cf6,0x914da9246b255416,
        0x8bab8eefb6409c1a,0x1ad089b6c2f7548e,
        0xae9672aba3d0c320,0xa184ac2473b529b1,
        0xda3c0f568cc4f3e8,0xc9e5d72d90a2741e,
        0x8865899617fb1871,0x7e2fa67c7a658892,
        0xaa7eebfb9df9de8d,0xddbb901b98feeab7,
        0xd51ea6fa85785631,0x552a74227f3ea565,
        0x8533285c936b35de,0xd53a88958f87275f,
        0xa67ff273b8460356,0x8a892abaf368f137,
        0xd01fef10a657842c,0x2d2b7569b0432d85,
        0x8213f56a67f6b29b,0x9c3b29620e29fc73,
        0xa298f2c501f45f42,0x8349f3ba91b47b8f,
        0xcb3f2f7642717713,0x241c70a936219a73,
        0xfe0efb53d30dd4d7,0xed238cd383aa0110,
        0x9ec95d1463e8a506,0xf4363804324a40aa,
        0xc67bb4597ce2ce48,0xb143c6053edcd0d5,
        0xf81aa16fdc1b81da,0xdd94b7868e94050a,
        0x9b10a4e5e9913128,0xca7cf2b4191c8326,
        0xc1d4ce1f63f57d72,0xfd1c2f611f63a3f0,
        0xf24a01a73cf2dccf,0xbc633b39673c8cec,
        0x976e41088617ca01,0xd5be0503e085d813,
        0xbd49d14aa79dbc82,0x4b2d8644d8a74e18,
        0xec9c459d51852ba2,0xddf8e7d60ed1219e,
        0x93e1ab8252f33b45,0xcabb90e5c942b503,
        0xb8da1662e7b00a17,0x3d6a751f3b936243,
        0xe7109bfba19c0c9d,0xcc512670a783ad4,
        0x906a617d450187e2,0x27fb2b80668b24c5,
        0xb484f9dc9641e9da,0xb1f9f660802dedf6,
        0xe1a63853bbd26451,0x5e7873f8a0396973,
        0x8d07e33455637eb2,0xdb0b487b6423e1e8,
        0xb049dc016abc5e5f,0x91ce1a9a3d2cda62,
        0xdc5c5301c56b75f7,0x7641a140cc7810fb,
        0x89b9b3e11b6329ba,0xa9e904c87fcb0a9d,
        0xac2820d9623bf429,0x546345fa9fbdcd44,
        0xd732290fbacaf133,0xa97c177947ad4095,
        0x867f59a9d4bed6c0,0x49ed8eabcccc485d,
        0xa81f301449ee8c70,0x5c68f256bfff5a74,
        0xd226fc195c6a2f8c,0x73832eec6fff3111,
        0x83585d8fd9c25db7,0xc831fd53c5ff7eab,
        0xa42e74f3d032f525,0xba3e7ca8b77f5e55,
        0xcd3a1230c43fb26f,0x28ce1bd2e55f35eb,
        0x80444b5e7aa7cf85,0x7980d163cf5b81b3,
        0xa0555e361951c366,0xd7e105bcc332621f,
        0xc86ab5c39fa63440,0x8dd9472bf3fefaa7,
        0xfa856334878fc150,0xb14f98f6f0feb951,
        0x9c935e00d4b9d8d2,0x6ed1bf9a569f33d3,
        0xc3b8358109e84f07,0xa862f80ec4700c8,
        0xf4a642e14c6262c8,0xcd27bb612758c0fa,
        0x98e7e9cccfbd7dbd,0x8038d51cb897789c,
        0xbf21e44003acdd2c,0xe0470a63e6bd56c3,
        0xeeea5d5004981478,0x1858ccfce06cac74,
        0x95527a5202df0ccb,0xf37801e0c43ebc8,
        0xbaa718e68396cffd,0xd30560258f54e6ba,
        0xe950df20247c83fd,0x47c6b82ef32a2069,
        0x91d28b7416cdd27e,0x4cdc331d57fa5441,
        0xb6472e511c81471d,0xe0133fe4adf8e952,
        0xe3d8f9e563a198e5,0x58180fddd97723a6,
        0x8e679c2f5e44ff8f,0x570f09eaa7ea7648,};
using powers = powers_template<>;

}

#endif

#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H
#define FASTFLOAT_DECIMAL_TO_BINARY_H

#include <cfloat>
#include <cinttypes>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>

namespace duckdb_fast_float {

// This will compute or rather approximate w * 5**q and return a pair of 64-bit words approximating
// the result, with the "high" part corresponding to the most significant bits and the
// low part corresponding to the least significant bits.
//
template <int bit_precision>
fastfloat_really_inline
value128 compute_product_approximation(int64_t q, uint64_t w) {
  const int index = 2 * int(q - powers::smallest_power_of_five);
  // For small values of q, e.g., q in [0,27], the answer is always exact because
  // The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
  // gives the exact answer.
  value128 firstproduct = full_multiplication(w, powers::power_of_five_128[index]);
  static_assert((bit_precision >= 0) && (bit_precision <= 64), " precision should  be in (0,64]");
  constexpr uint64_t precision_mask = (bit_precision < 64) ?
               (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)
               : uint64_t(0xFFFFFFFFFFFFFFFF);
  if((firstproduct.high & precision_mask) == precision_mask) { // could further guard with  (lower + w < lower)
    // regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed.
    value128 secondproduct = full_multiplication(w, powers::power_of_five_128[index + 1]);
    firstproduct.low += secondproduct.high;
    if(secondproduct.high > firstproduct.low) {
      firstproduct.high++;
    }
  }
  return firstproduct;
}

namespace detail {
/**
 * For q in (0,350), we have that
 *  f = (((152170 + 65536) * q ) >> 16);
 * is equal to
 *   floor(p) + q
 * where
 *   p = log(5**q)/log(2) = q * log(5)/log(2)
 *
 * For negative values of q in (-400,0), we have that 
 *  f = (((152170 + 65536) * q ) >> 16);
 * is equal to 
 *   -ceil(p) + q
 * where
 *   p = log(5**-q)/log(2) = -q * log(5)/log(2)
 */
  fastfloat_really_inline int power(int q)  noexcept  {
    return (((152170 + 65536) * q) >> 16) + 63;
  }
} // namespace detail


// w * 10 ** q
// The returned value should be a valid ieee64 number that simply need to be packed.
// However, in some very rare cases, the computation will fail. In such cases, we
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
// in such cases.
template <typename binary>
fastfloat_really_inline
adjusted_mantissa compute_float(int64_t q, uint64_t w)  noexcept  {
  adjusted_mantissa answer;
  if ((w == 0) || (q < binary::smallest_power_of_ten())) {
    answer.power2 = 0;
    answer.mantissa = 0;
    // result should be zero
    return answer;
  }
  if (q > binary::largest_power_of_ten()) {
    // we want to get infinity:
    answer.power2 = binary::infinite_power();
    answer.mantissa = 0;
    return answer;
  }
  // At this point in time q is in [powers::smallest_power_of_five, powers::largest_power_of_five].

  // We want the most significant bit of i to be 1. Shift if needed.
  int lz = leading_zeroes(w);
  w <<= lz;

  // The required precision is binary::mantissa_explicit_bits() + 3 because
  // 1. We need the implicit bit
  // 2. We need an extra bit for rounding purposes
  // 3. We might lose a bit due to the "upperbit" routine (result too small, requiring a shift)

  value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);
  if(product.low == 0xFFFFFFFFFFFFFFFF) { //  could guard it further
    // In some very rare cases, this could happen, in which case we might need a more accurate
    // computation that what we can provide cheaply. This is very, very unlikely.
    //
    const bool inside_safe_exponent = (q >= -27) && (q <= 55); // always good because 5**q <2**128 when q>=0, 
    // and otherwise, for q<0, we have 5**-q<2**64 and the 128-bit reciprocal allows for exact computation.
    if(!inside_safe_exponent) {
      answer.power2 = -1; // This (a negative value) indicates an error condition.
      return answer;
    }
  }
  // The "compute_product_approximation" function can be slightly slower than a branchless approach:
  // value128 product = compute_product(q, w);
  // but in practice, we can win big with the compute_product_approximation if its additional branch
  // is easily predicted. Which is best is data specific.
  int upperbit = int(product.high >> 63);

  answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);

  answer.power2 = int(detail::power(int(q)) + upperbit - lz - binary::minimum_exponent());
  if (answer.power2 <= 0) { // we have a subnormal?
    // Here have that answer.power2 <= 0 so -answer.power2 >= 0
    if(-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
      answer.power2 = 0;
      answer.mantissa = 0;
      // result should be zero
      return answer;
    }
    // next line is safe because -answer.power2 + 1 < 64
    answer.mantissa >>= -answer.power2 + 1;
    // Thankfully, we can't have both "round-to-even" and subnormals because
    // "round-to-even" only occurs for powers close to 0.
    answer.mantissa += (answer.mantissa & 1); // round up
    answer.mantissa >>= 1;
    // There is a weird scenario where we don't have a subnormal but just.
    // Suppose we start with 2.2250738585072013e-308, we end up
    // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal
    // whereas 0x40000000000000 x 2^-1023-53  is normal. Now, we need to round
    // up 0x3fffffffffffff x 2^-1023-53  and once we do, we are no longer
    // subnormal, but we can only know this after rounding.
    // So we only declare a subnormal if we are smaller than the threshold.
    answer.power2 = (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) ? 0 : 1;
    return answer;
  }

  // usually, we round *up*, but if we fall right in between and and we have an
  // even basis, we need to round down
  // We are only concerned with the cases where 5**q fits in single 64-bit word.
  if ((product.low <= 1) &&  (q >= binary::min_exponent_round_to_even()) && (q <= binary::max_exponent_round_to_even()) &&
      ((answer.mantissa & 3) == 1) ) { // we may fall between two floats!
    // To be in-between two floats we need that in doing
    //   answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
    // ... we dropped out only zeroes. But if this happened, then we can go back!!!
    if((answer.mantissa  << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) ==  product.high) {
      answer.mantissa &= ~uint64_t(1);          // flip it so that we do not round up
    }
  }

  answer.mantissa += (answer.mantissa & 1); // round up
  answer.mantissa >>= 1;
  if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) {
    answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits());
    answer.power2++; // undo previous addition
  }

  answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits());
  if (answer.power2 >= binary::infinite_power()) { // infinity
    answer.power2 = binary::infinite_power();
    answer.mantissa = 0;
  }
  return answer;
}


} // namespace duckdb_fast_float

#endif


#ifndef FASTFLOAT_ASCII_NUMBER_H
#define FASTFLOAT_ASCII_NUMBER_H

#include <cstdio>
#include <cctype>
#include <cstdint>
#include <cstring>


namespace duckdb_fast_float {

// Next function can be micro-optimized, but compilers are entirely
// able to optimize it well.
fastfloat_really_inline bool is_integer(char c)  noexcept  { return c >= '0' && c <= '9'; }

fastfloat_really_inline uint64_t byteswap(uint64_t val) {
  return (val & 0xFF00000000000000) >> 56
    | (val & 0x00FF000000000000) >> 40
    | (val & 0x0000FF0000000000) >> 24
    | (val & 0x000000FF00000000) >> 8
    | (val & 0x00000000FF000000) << 8
    | (val & 0x0000000000FF0000) << 24
    | (val & 0x000000000000FF00) << 40
    | (val & 0x00000000000000FF) << 56;
}

fastfloat_really_inline uint64_t read_u64(const char *chars) {
  uint64_t val;
  ::memcpy(&val, chars, sizeof(uint64_t));
#if FASTFLOAT_IS_BIG_ENDIAN == 1
  // Need to read as-if the number was in little-endian order.
  val = byteswap(val);
#endif
  return val;
}

fastfloat_really_inline void write_u64(uint8_t *chars, uint64_t val) {
#if FASTFLOAT_IS_BIG_ENDIAN == 1
  // Need to read as-if the number was in little-endian order.
  val = byteswap(val);
#endif
  ::memcpy(chars, &val, sizeof(uint64_t));
}

// credit  @aqrit
fastfloat_really_inline uint32_t  parse_eight_digits_unrolled(uint64_t val) {
  const uint64_t mask = 0x000000FF000000FF;
  const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
  const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
  val -= 0x3030303030303030;
  val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
  val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
  return uint32_t(val);
}

fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars)  noexcept  {
  return parse_eight_digits_unrolled(read_u64(chars));
}

// credit @aqrit
fastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val)  noexcept  {
  return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
     0x8080808080808080));
}

fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars)  noexcept  {
  return is_made_of_eight_digits_fast(read_u64(chars));
}

struct parsed_number_string {
  int64_t exponent;
  uint64_t mantissa;
  const char *lastmatch;
  bool negative;
  bool valid;
  bool too_many_digits;
};


// Assuming that you use no more than 19 digits, this will
// parse an ASCII string.
fastfloat_really_inline
parsed_number_string parse_number_string(const char *p, const char *pend, chars_format fmt) noexcept {
  parsed_number_string answer;
  answer.valid = false;
  answer.too_many_digits = false;
  answer.negative = (*p == '-');
  if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
    ++p;
    if (p == pend) {
      return answer;
    }
    if (!is_integer(*p) && (*p != '.')) { // a  sign must be followed by an integer or the dot
      return answer;
    }
  }
  const char *const start_digits = p;

  uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)

  while ((p != pend) && is_integer(*p)) {
    // a multiplication by 10 is cheaper than an arbitrary integer
    // multiplication
    i = 10 * i +
        uint64_t(*p - '0'); // might overflow, we will handle the overflow later
    ++p;
  }
  const char *const end_of_integer_part = p;
  int64_t digit_count = int64_t(end_of_integer_part - start_digits);
  int64_t exponent = 0;
  if ((p != pend) && (*p == '.')) {
    ++p;
  // Fast approach only tested under little endian systems
  if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
    i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
    p += 8;
    if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
      i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
      p += 8;
    }
  }
    while ((p != pend) && is_integer(*p)) {
      uint8_t digit = uint8_t(*p - '0');
      ++p;
      i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
    }
    exponent = end_of_integer_part + 1 - p;
    digit_count -= exponent;
  }
  // we must have encountered at least one integer!
  if (digit_count == 0) {
    return answer;
  }
  int64_t exp_number = 0;            // explicit exponential part
  if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) {
    const char * location_of_e = p;
    ++p;
    bool neg_exp = false;
    if ((p != pend) && ('-' == *p)) {
      neg_exp = true;
      ++p;
    } else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
      ++p;
    }
    if ((p == pend) || !is_integer(*p)) {
      if(!(fmt & chars_format::fixed)) {
        // We are in error.
        return answer;
      }
      // Otherwise, we will be ignoring the 'e'.
      p = location_of_e;
    } else {
      while ((p != pend) && is_integer(*p)) {
        uint8_t digit = uint8_t(*p - '0');
        if (exp_number < 0x10000) {
          exp_number = 10 * exp_number + digit;
        }
        ++p;
      }
      if(neg_exp) { exp_number = - exp_number; }
      exponent += exp_number;
    }
  } else {
    // If it scientific and not fixed, we have to bail out.
    if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }
  }
  answer.lastmatch = p;
  answer.valid = true;

  // If we frequently had to deal with long strings of digits,
  // we could extend our code by using a 128-bit integer instead
  // of a 64-bit integer. However, this is uncommon.
  //
  // We can deal with up to 19 digits.
  if (digit_count > 19) { // this is uncommon
    // It is possible that the integer had an overflow.
    // We have to handle the case where we have 0.0000somenumber.
    // We need to be mindful of the case where we only have zeroes...
    // E.g., 0.000000000...000.
    const char *start = start_digits;
    while ((start != pend) && (*start == '0' || *start == '.')) {
      if(*start == '0') { digit_count --; }
      start++;
    }
    if (digit_count > 19) {
      answer.too_many_digits = true;
      // Let us start again, this time, avoiding overflows.
      i = 0;
      p = start_digits;
      const uint64_t minimal_nineteen_digit_integer{1000000000000000000};
      while((i < minimal_nineteen_digit_integer) && (p != pend) && is_integer(*p)) {
        i = i * 10 + uint64_t(*p - '0');
        ++p;
      }
      if (i >= minimal_nineteen_digit_integer) { // We have a big integers
        exponent = end_of_integer_part - p + exp_number;
      } else { // We have a value with a fractional component.
          p++; // skip the '.'
          const char *first_after_period = p;
          while((i < minimal_nineteen_digit_integer) && (p != pend) && is_integer(*p)) {
            i = i * 10 + uint64_t(*p - '0');
            ++p;
          }
          exponent = first_after_period - p + exp_number;
      }
      // We have now corrected both exponent and i, to a truncated value
    }
  }
  answer.exponent = exponent;
  answer.mantissa = i;
  return answer;
}


// This should always succeed since it follows a call to parse_number_string
// This function could be optimized. In particular, we could stop after 19 digits
// and try to bail out. Furthermore, we should be able to recover the computed
// exponent from the pass in parse_number_string.
fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) noexcept {
  decimal answer;
  answer.num_digits = 0;
  answer.decimal_point = 0;
  answer.truncated = false;
  answer.negative = (*p == '-');
  if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
    ++p;
  }
  // skip leading zeroes
  while ((p != pend) && (*p == '0')) {
    ++p;
  }
  while ((p != pend) && is_integer(*p)) {
    if (answer.num_digits < max_digits) {
      answer.digits[answer.num_digits] = uint8_t(*p - '0');
    }
    answer.num_digits++;
    ++p;
  }
  if ((p != pend) && (*p == '.')) {
    ++p;
    const char *first_after_period = p;
    // if we have not yet encountered a zero, we have to skip it as well
    if(answer.num_digits == 0) {
      // skip zeros
      while ((p != pend) && (*p == '0')) {
       ++p;
      }
    }
    // We expect that this loop will often take the bulk of the running time
    // because when a value has lots of digits, these digits often
    while ((p + 8 <= pend) && (answer.num_digits + 8 < max_digits)) {
      uint64_t val = read_u64(p);
      if(! is_made_of_eight_digits_fast(val)) { break; }
      // We have eight digits, process them in one go!
      val -= 0x3030303030303030;
      write_u64(answer.digits + answer.num_digits, val);
      answer.num_digits += 8;
      p += 8;
    }
    while ((p != pend) && is_integer(*p)) {
      if (answer.num_digits < max_digits) {
        answer.digits[answer.num_digits] = uint8_t(*p - '0');
      }
      answer.num_digits++;
      ++p;
    }
    answer.decimal_point = int32_t(first_after_period - p);
  }
  // We want num_digits to be the number of significant digits, excluding
  // leading *and* trailing zeros! Otherwise the truncated flag later is
  // going to be misleading.
  if(answer.num_digits > 0) {
    // We potentially need the answer.num_digits > 0 guard because we
    // prune leading zeros. So with answer.num_digits > 0, we know that
    // we have at least one non-zero digit.
    const char *preverse = p - 1;
    int32_t trailing_zeros = 0;
    while ((*preverse == '0') || (*preverse == '.')) {
      if(*preverse == '0') { trailing_zeros++; };
      --preverse;
    }
    answer.decimal_point += int32_t(answer.num_digits);
    answer.num_digits -= uint32_t(trailing_zeros);
  }
  if(answer.num_digits > max_digits) {
    answer.truncated = true;
    answer.num_digits = max_digits;
  }
  if ((p != pend) && (('e' == *p) || ('E' == *p))) {
    ++p;
    bool neg_exp = false;
    if ((p != pend) && ('-' == *p)) {
      neg_exp = true;
      ++p;
    } else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
      ++p;
    }
    int32_t exp_number = 0; // exponential part
    while ((p != pend) && is_integer(*p)) {
      uint8_t digit = uint8_t(*p - '0');
      if (exp_number < 0x10000) {
        exp_number = 10 * exp_number + digit;
      }
      ++p;
    }
    answer.decimal_point += (neg_exp ? -exp_number : exp_number);
  }
  // In very rare cases, we may have fewer than 19 digits, we want to be able to reliably
  // assume that all digits up to max_digit_without_overflow have been initialized.
  for(uint32_t i = answer.num_digits; i < max_digit_without_overflow; i++) { answer.digits[i] = 0; }

  return answer;
}
} // namespace duckdb_fast_float

#endif


#ifndef FASTFLOAT_GENERIC_DECIMAL_TO_BINARY_H
#define FASTFLOAT_GENERIC_DECIMAL_TO_BINARY_H

/**
 * This code is meant to handle the case where we have more than 19 digits.
 *
 * It is based on work by Nigel Tao (at https://github.com/google/wuffs/)
 * who credits Ken Thompson for the design (via a reference to the Go source
 * code).
 *
 * Rob Pike suggested that this algorithm be called "Simple Decimal Conversion".
 *
 * It is probably not very fast but it is a fallback that should almost never
 * be used in real life. Though it is not fast, it is "easily" understood and debugged.
 **/
#include <cstdint>

namespace duckdb_fast_float {

namespace detail {

// remove all final zeroes
inline void trim(decimal &h) {
  while ((h.num_digits > 0) && (h.digits[h.num_digits - 1] == 0)) {
    h.num_digits--;
  }
}



inline uint32_t number_of_digits_decimal_left_shift(const decimal &h, uint32_t shift) {
  shift &= 63;
  const static uint16_t number_of_digits_decimal_left_shift_table[65] = {
    0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
    0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,
    0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,
    0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, 0x5180, 0x5998, 0x59B0,
    0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, 0x72AA,
    0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC,
    0x8C02, 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C,
    0x051C, 0x051C,
  };
  uint32_t x_a = number_of_digits_decimal_left_shift_table[shift];
  uint32_t x_b = number_of_digits_decimal_left_shift_table[shift + 1];
  uint32_t num_new_digits = x_a >> 11;
  uint32_t pow5_a = 0x7FF & x_a;
  uint32_t pow5_b = 0x7FF & x_b;
  const static uint8_t
    number_of_digits_decimal_left_shift_table_powers_of_5[0x051C] = {
        5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3,
        9, 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8,
        1, 2, 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1,
        0, 3, 5, 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, 5, 1, 5, 2, 5, 8,
        7, 8, 9, 0, 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6,
        9, 7, 2, 6, 5, 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5,
        3, 6, 7, 4, 3, 1, 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3,
        1, 2, 5, 2, 3, 8, 4, 1, 8, 5, 7, 9, 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0,
        9, 2, 8, 9, 5, 5, 0, 7, 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, 4, 4, 7, 7, 5, 3,
        9, 0, 6, 2, 5, 2, 9, 8, 0, 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1,
        4, 9, 0, 1, 1, 6, 1, 1, 9, 3, 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8,
        0, 5, 9, 6, 9, 2, 3, 8, 2, 8, 1, 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4,
        6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6, 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5,
        7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5, 7, 4, 6, 1, 5, 4, 7, 8, 5, 1, 5,
        6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0, 7, 7, 3, 9, 2, 5, 7, 8, 1, 2,
        5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6, 9, 6, 2, 8, 9, 0, 6, 2, 5,
        1, 1, 6, 4, 1, 5, 3, 2, 1, 8, 2, 6, 9, 3, 4, 8, 1, 4, 4, 5, 3, 1, 2, 5,
        5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, 6, 7, 4, 0, 7, 2, 2, 6, 5, 6, 2, 5,
        2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6, 1, 3, 2, 8, 1, 2,
        5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8, 0, 6, 6, 4, 0,
        6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9, 0, 3, 3, 2,
        0, 3, 1, 2, 5, 3, 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2, 9, 5, 1,
        6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, 9, 8, 9, 4, 0, 3, 5, 4, 5, 8, 5, 6,
        4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, 7, 0, 1, 7, 7, 2,
        9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5,
        0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7,
        3, 7, 3, 6, 7, 5, 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5,
        6, 2, 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9,
        3, 7, 9, 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, 8, 6, 0, 8, 0, 8,
        0, 1, 4, 8, 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0,
        9, 4, 3, 0, 4, 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2,
        5, 1, 4, 2, 1, 0, 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2,
        4, 8, 5, 3, 5, 1, 5, 6, 2, 5, 7, 1, 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0,
        0, 1, 8, 5, 8, 7, 1, 1, 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, 5, 3, 5, 5, 2, 7,
        1, 3, 6, 7, 8, 8, 0, 0, 5, 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8,
        9, 0, 6, 2, 5, 1, 7, 7, 6, 3, 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4,
        6, 7, 7, 8, 1, 0, 6, 6, 8, 9, 4, 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1,
        9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3, 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5,
        6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8, 5, 0, 0, 6, 2, 6, 1, 6, 1, 6, 9,
        4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2, 5, 2, 2, 2, 0, 4, 4, 6, 0, 4,
        9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6, 3, 3, 3, 6, 1, 8, 1, 6, 4,
        0, 6, 2, 5, 1, 1, 1, 0, 2, 2, 3, 0, 2, 4, 6, 2, 5, 1, 5, 6, 5, 4, 0, 4,
        2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, 2, 0, 3, 1, 2, 5, 5, 5, 5, 1, 1, 1,
        5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5, 8, 3, 4, 0, 4, 5,
        4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5, 6, 2, 8, 9, 1,
        3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8, 1, 2, 5, 1,
        3, 8, 7, 7, 7, 8, 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9, 5, 3, 9,
        5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, 6, 2, 5, 6, 9, 3, 8, 8, 9, 3, 9, 0,
        3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, 5, 5, 6, 7, 6, 2,
        6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1,
        8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5,
        1, 7, 3, 4, 7, 2, 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2,
        4, 4, 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1,
        7, 3, 7, 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, 2, 4, 0, 6, 9, 5,
        9, 5, 3, 3, 6, 9, 1, 4, 0, 6, 2, 5,
  };
  const uint8_t *pow5 =
      &number_of_digits_decimal_left_shift_table_powers_of_5[pow5_a];
  uint32_t i = 0;
  uint32_t n = pow5_b - pow5_a;
  for (; i < n; i++) {
    if (i >= h.num_digits) {
      return num_new_digits - 1;
    } else if (h.digits[i] == pow5[i]) {
      continue;
    } else if (h.digits[i] < pow5[i]) {
      return num_new_digits - 1;
    } else {
      return num_new_digits;
    }
  }
  return num_new_digits;
}

inline uint64_t round(decimal &h) {
  if ((h.num_digits == 0) || (h.decimal_point < 0)) {
    return 0;
  } else if (h.decimal_point > 18) {
    return UINT64_MAX;
  }
  // at this point, we know that h.decimal_point >= 0
  uint32_t dp = uint32_t(h.decimal_point);
  uint64_t n = 0;
  for (uint32_t i = 0; i < dp; i++) {
    n = (10 * n) + ((i < h.num_digits) ? h.digits[i] : 0);
  }
  bool round_up = false;
  if (dp < h.num_digits) {
    round_up = h.digits[dp] >= 5; // normally, we round up  
    // but we may need to round to even!
    if ((h.digits[dp] == 5) && (dp + 1 == h.num_digits)) {
      round_up = h.truncated || ((dp > 0) && (1 & h.digits[dp - 1]));
    }
  }
  if (round_up) {
    n++;
  }
  return n;
}

// computes h * 2^-shift
inline void decimal_left_shift(decimal &h, uint32_t shift) {
  if (h.num_digits == 0) {
    return;
  }
  uint32_t num_new_digits = number_of_digits_decimal_left_shift(h, shift);
  int32_t read_index = int32_t(h.num_digits - 1);
  uint32_t write_index = h.num_digits - 1 + num_new_digits;
  uint64_t n = 0;

  while (read_index >= 0) {
    n += uint64_t(h.digits[read_index]) << shift;
    uint64_t quotient = n / 10;
    uint64_t remainder = n - (10 * quotient);
    if (write_index < max_digits) {
      h.digits[write_index] = uint8_t(remainder);
    } else if (remainder > 0) {
      h.truncated = true;
    }
    n = quotient;
    write_index--;
    read_index--;
  }
  while (n > 0) {
    uint64_t quotient = n / 10;
    uint64_t remainder = n - (10 * quotient);
    if (write_index < max_digits) {
      h.digits[write_index] = uint8_t(remainder);
    } else if (remainder > 0) {
      h.truncated = true;
    }
    n = quotient;
    write_index--;
  }
  h.num_digits += num_new_digits;
  if (h.num_digits > max_digits) {
    h.num_digits = max_digits;
  }
  h.decimal_point += int32_t(num_new_digits);
  trim(h);
}

// computes h * 2^shift
inline void decimal_right_shift(decimal &h, uint32_t shift) {
  uint32_t read_index = 0;
  uint32_t write_index = 0;

  uint64_t n = 0;

  while ((n >> shift) == 0) {
    if (read_index < h.num_digits) {
      n = (10 * n) + h.digits[read_index++];
    } else if (n == 0) {
      return;
    } else {
      while ((n >> shift) == 0) {
        n = 10 * n;
        read_index++;
      }
      break;
    }
  }
  h.decimal_point -= int32_t(read_index - 1);
  if (h.decimal_point < -decimal_point_range) { // it is zero
    h.num_digits = 0;
    h.decimal_point = 0;
    h.negative = false;
    h.truncated = false;
    return;
  }
  uint64_t mask = (uint64_t(1) << shift) - 1;
  while (read_index < h.num_digits) {
    uint8_t new_digit = uint8_t(n >> shift);
    n = (10 * (n & mask)) + h.digits[read_index++];
    h.digits[write_index++] = new_digit;
  }
  while (n > 0) {
    uint8_t new_digit = uint8_t(n >> shift);
    n = 10 * (n & mask);
    if (write_index < max_digits) {
      h.digits[write_index++] = new_digit;
    } else if (new_digit > 0) {
      h.truncated = true;
    }
  }
  h.num_digits = write_index;
  trim(h);
}

} // namespace detail

template <typename binary>
adjusted_mantissa compute_float(decimal &d) {
  adjusted_mantissa answer;
  if (d.num_digits == 0) {
    // should be zero
    answer.power2 = 0;
    answer.mantissa = 0;
    return answer;
  }
  // At this point, going further, we can assume that d.num_digits > 0.
  //
  // We want to guard against excessive decimal point values because
  // they can result in long running times. Indeed, we do
  // shifts by at most 60 bits. We have that log(10**400)/log(2**60) ~= 22
  // which is fine, but log(10**299995)/log(2**60) ~= 16609 which is not
  // fine (runs for a long time).
  //
  if(d.decimal_point < -324) {
    // We have something smaller than 1e-324 which is always zero
    // in binary64 and binary32.
    // It should be zero.
    answer.power2 = 0;
    answer.mantissa = 0;
    return answer;
  } else if(d.decimal_point >= 310) {
    // We have something at least as large as 0.1e310 which is
    // always infinite.  
    answer.power2 = binary::infinite_power();
    answer.mantissa = 0;
    return answer;
  }
  static const uint32_t max_shift = 60;
  static const uint32_t num_powers = 19;
  static const uint8_t decimal_powers[19] = {
      0,  3,  6,  9,  13, 16, 19, 23, 26, 29, //
      33, 36, 39, 43, 46, 49, 53, 56, 59,     //
  };
  int32_t exp2 = 0;
  while (d.decimal_point > 0) {
    uint32_t n = uint32_t(d.decimal_point);
    uint32_t shift = (n < num_powers) ? decimal_powers[n] : max_shift;
    detail::decimal_right_shift(d, shift);
    if (d.decimal_point < -decimal_point_range) {
      // should be zero
      answer.power2 = 0;
      answer.mantissa = 0;
      return answer;
    }
    exp2 += int32_t(shift);
  }
  // We shift left toward [1/2 ... 1].
  while (d.decimal_point <= 0) {
    uint32_t shift;
    if (d.decimal_point == 0) {
      if (d.digits[0] >= 5) {
        break;
      }
      shift = (d.digits[0] < 2) ? 2 : 1;
    } else {
      uint32_t n = uint32_t(-d.decimal_point);
      shift = (n < num_powers) ? decimal_powers[n] : max_shift;
    }
    detail::decimal_left_shift(d, shift);
    if (d.decimal_point > decimal_point_range) {
      // we want to get infinity:
      answer.power2 = binary::infinite_power();
      answer.mantissa = 0;
      return answer;
    }
    exp2 -= int32_t(shift);
  }
  // We are now in the range [1/2 ... 1] but the binary format uses [1 ... 2].
  exp2--;
  constexpr int32_t minimum_exponent = binary::minimum_exponent();
  while ((minimum_exponent + 1) > exp2) {
    uint32_t n = uint32_t((minimum_exponent + 1) - exp2);
    if (n > max_shift) {
      n = max_shift;
    }
    detail::decimal_right_shift(d, n);
    exp2 += int32_t(n);
  }
  if ((exp2 - minimum_exponent) >= binary::infinite_power()) {
    answer.power2 = binary::infinite_power();
    answer.mantissa = 0;
    return answer;
  }

  const int mantissa_size_in_bits = binary::mantissa_explicit_bits() + 1;
  detail::decimal_left_shift(d, mantissa_size_in_bits);

  uint64_t mantissa = detail::round(d);
  // It is possible that we have an overflow, in which case we need
  // to shift back.
  if(mantissa >= (uint64_t(1) << mantissa_size_in_bits)) {
    detail::decimal_right_shift(d, 1);
    exp2 += 1;
    mantissa = detail::round(d);
    if ((exp2 - minimum_exponent) >= binary::infinite_power()) {
      answer.power2 = binary::infinite_power();
      answer.mantissa = 0;
      return answer;
    }
  }
  answer.power2 = exp2  - binary::minimum_exponent();
  if(mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) { answer.power2--; }
  answer.mantissa = mantissa & ((uint64_t(1) << binary::mantissa_explicit_bits()) - 1);
  return answer;
}

template <typename binary>
adjusted_mantissa parse_long_mantissa(const char *first, const char* last) {
    decimal d = parse_decimal(first, last);
    return compute_float<binary>(d);
}

} // namespace duckdb_fast_float
#endif


#ifndef FASTFLOAT_PARSE_NUMBER_H
#define FASTFLOAT_PARSE_NUMBER_H

#include <cassert>
#include <cmath>
#include <cstring>
#include <limits>
#include <system_error>

namespace duckdb_fast_float {


namespace detail {
/**
 * Special case +inf, -inf, nan, infinity, -infinity.
 * The case comparisons could be made much faster given that we know that the
 * strings a null-free and fixed.
 **/
template <typename T>
from_chars_result parse_infnan(const char *first, const char *last, T &value)  noexcept  {
  from_chars_result answer;
  answer.ptr = first;
  answer.ec = std::errc(); // be optimistic
  bool minusSign = false;
  if (*first == '-') { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
      minusSign = true;
      ++first;
  }
  if (last - first >= 3) {
    if (fastfloat_strncasecmp(first, "nan", 3)) {
      answer.ptr = (first += 3);
      value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
      // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
      if(first != last && *first == '(') {
        for(const char* ptr = first + 1; ptr != last; ++ptr) {
          if (*ptr == ')') {
            answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
            break;
          }
          else if(!(('a' <= *ptr && *ptr <= 'z') || ('A' <= *ptr && *ptr <= 'Z') || ('0' <= *ptr && *ptr <= '9') || *ptr == '_'))
            break; // forbidden char, not nan(n-char-seq-opt)
        }
      }
      return answer;
    }
    if (fastfloat_strncasecmp(first, "inf", 3)) {
      if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, "inity", 5)) {
        answer.ptr = first + 8;
      } else {
        answer.ptr = first + 3;
      }
      value = minusSign ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity();
      return answer;
    }
  }
  answer.ec = std::errc::invalid_argument;
  return answer;
}

template<typename T>
fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value) {
  uint64_t word = am.mantissa;
  word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
  word = negative
  ? word | (uint64_t(1) << binary_format<T>::sign_index()) : word;
#if FASTFLOAT_IS_BIG_ENDIAN == 1
   if (std::is_same<T, float>::value) {
     ::memcpy(&value, (char *)&word + 4, sizeof(T)); // extract value at offset 4-7 if float on big-endian
   } else {
     ::memcpy(&value, &word, sizeof(T));
   }
#else
   // For little-endian systems:
   ::memcpy(&value, &word, sizeof(T));
#endif
}

} // namespace detail



template<typename T>
from_chars_result from_chars(const char *first, const char *last,
                             T &value, chars_format fmt /*= chars_format::general*/)  noexcept  {
  static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");


  from_chars_result answer;
  if (first == last) {
    answer.ec = std::errc::invalid_argument;
    answer.ptr = first;
    return answer;
  }
  parsed_number_string pns = parse_number_string(first, last, fmt);
  if (!pns.valid) {
    return detail::parse_infnan(first, last, value);
  }
  answer.ec = std::errc(); // be optimistic
  answer.ptr = pns.lastmatch;
  // Next is Clinger's fast path.
  if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path() && !pns.too_many_digits) {
    value = T(pns.mantissa);
    if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
    else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
    if (pns.negative) { value = -value; }
    return answer;
  }
  adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
  if(pns.too_many_digits) {
    if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
      am.power2 = -1; // value is invalid.
    }
  }
  // If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa) and we have an invalid power (am.power2 < 0),
  // then we need to go the long way around again. This is very uncommon.
  if(am.power2 < 0) { am = parse_long_mantissa<binary_format<T>>(first,last); }
  detail::to_float(pns.negative, am, value);
  return answer;
}

} // namespace duckdb_fast_float

#endif



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





namespace duckdb {

class PipeFileSystem : public FileSystem {
public:
	static unique_ptr<FileHandle> OpenPipe(unique_ptr<FileHandle> handle);

	int64_t Read(FileHandle &handle, void *buffer, int64_t nr_bytes) override;
	int64_t Write(FileHandle &handle, void *buffer, int64_t nr_bytes) override;

	int64_t GetFileSize(FileHandle &handle) override;

	void Reset(FileHandle &handle) override;
	bool OnDiskFile(FileHandle &handle) override {
		return false;
	};
	bool CanSeek() override {
		return false;
	}
	void FileSync(FileHandle &handle) override;

	std::string GetName() const override {
		return "PipeFileSystem";
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/random_engine.hpp
//
//
//===----------------------------------------------------------------------===//





#include <random>

namespace duckdb {
class ClientContext;
struct RandomState;

struct RandomEngine {
	RandomEngine(int64_t seed = -1);
	~RandomEngine();

public:
	//! Generate a random number between min and max
	double NextRandom(double min, double max);

	//! Generate a random number between 0 and 1
	double NextRandom();
	uint32_t NextRandomInteger();

	void SetSeed(uint32_t seed);

	static RandomEngine &Get(ClientContext &context);

private:
	unique_ptr<RandomState> random_state;
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #5
// See the end of this file for a list

/*
 * PCG Random Number Generation for C++
 *
 * Copyright 2014-2019 Melissa O'Neill <oneill@pcg-random.org>,
 *                     and the PCG Project contributors.
 *
 * SPDX-License-Identifier: (Apache-2.0 OR MIT)
 *
 * Licensed under the Apache License, Version 2.0 (provided in
 * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
 * or under the MIT license (provided in LICENSE-MIT.txt and at
 * http://opensource.org/licenses/MIT), at your option. This file may not
 * be copied, modified, or distributed except according to those terms.
 *
 * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
 * express or implied.  See your chosen license for details.
 *
 * For additional information about the PCG random number generation scheme,
 * visit http://www.pcg-random.org/.
 */

/*
 * This code provides the reference implementation of the PCG family of
 * random number generators.  The code is complex because it implements
 *
 *      - several members of the PCG family, specifically members corresponding
 *        to the output functions:
 *             - XSH RR         (good for 64-bit state, 32-bit output)
 *             - XSH RS         (good for 64-bit state, 32-bit output)
 *             - XSL RR         (good for 128-bit state, 64-bit output)
 *             - RXS M XS       (statistically most powerful generator)
 *             - XSL RR RR      (good for 128-bit state, 128-bit output)
 *             - and RXS, RXS M, XSH, XSL       (mostly for testing)
 *      - at potentially *arbitrary* bit sizes
 *      - with four different techniques for random streams (MCG, one-stream
 *        LCG, settable-stream LCG, unique-stream LCG)
 *      - and the extended generation schemes allowing arbitrary periods
 *      - with all features of C++11 random number generation (and more),
 *        some of which are somewhat painful, including
 *            - initializing with a SeedSequence which writes 32-bit values
 *              to memory, even though the state of the generator may not
 *              use 32-bit values (it might use smaller or larger integers)
 *            - I/O for RNGs and a prescribed format, which needs to handle
 *              the issue that 8-bit and 128-bit integers don't have working
 *              I/O routines (e.g., normally 8-bit = char, not integer)
 *            - equality and inequality for RNGs
 *      - and a number of convenience typedefs to mask all the complexity
 *
 * The code employes a fairly heavy level of abstraction, and has to deal
 * with various C++ minutia.  If you're looking to learn about how the PCG
 * scheme works, you're probably best of starting with one of the other
 * codebases (see www.pcg-random.org).  But if you're curious about the
 * constants for the various output functions used in those other, simpler,
 * codebases, this code shows how they are calculated.
 *
 * On the positive side, at least there are convenience typedefs so that you
 * can say
 *
 *      pcg32 myRNG;
 *
 * rather than:
 *
 *      pcg_detail::engine<
 *          uint32_t,                                           // Output Type
 *          uint64_t,                                           // State Type
 *          pcg_detail::xsh_rr_mixin<uint32_t, uint64_t>, true, // Output Func
 *          pcg_detail::specific_stream<uint64_t>,              // Stream Kind
 *          pcg_detail::default_multiplier<uint64_t>            // LCG Mult
 *      > myRNG;
 *
 */

#ifndef PCG_RAND_HPP_INCLUDED
#define PCG_RAND_HPP_INCLUDED 1

#include <algorithm>
#include <cinttypes>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <limits>
#include <iostream>
#include <iterator>
#include <type_traits>
#include <utility>
#include <locale>
#include <new>
#include <stdexcept>

#ifdef _MSC_VER
    #pragma warning(disable:4146)
#endif

#ifdef _MSC_VER
    #define PCG_ALWAYS_INLINE __forceinline
#elif __GNUC__
    #define PCG_ALWAYS_INLINE __attribute__((always_inline))
#else
    #define PCG_ALWAYS_INLINE inline
#endif

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

/*
 * The pcg_extras namespace contains some support code that is likley to
 * be useful for a variety of RNGs, including:
 *      - 128-bit int support for platforms where it isn't available natively
 *      - bit twiddling operations
 *      - I/O of 128-bit and 8-bit integers
 *      - Handling the evilness of SeedSeq
 *      - Support for efficiently producing random numbers less than a given
 *        bound
 */



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #5
// See the end of this file for a list

/*
 * PCG Random Number Generation for C++
 *
 * Copyright 2014-2017 Melissa O'Neill <oneill@pcg-random.org>,
 *                     and the PCG Project contributors.
 *
 * SPDX-License-Identifier: (Apache-2.0 OR MIT)
 *
 * Licensed under the Apache License, Version 2.0 (provided in
 * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
 * or under the MIT license (provided in LICENSE-MIT.txt and at
 * http://opensource.org/licenses/MIT), at your option. This file may not
 * be copied, modified, or distributed except according to those terms.
 *
 * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
 * express or implied.  See your chosen license for details.
 *
 * For additional information about the PCG random number generation scheme,
 * visit http://www.pcg-random.org/.
 */

/*
 * This file provides support code that is useful for random-number generation
 * but not specific to the PCG generation scheme, including:
 *      - 128-bit int support for platforms where it isn't available natively
 *      - bit twiddling operations
 *      - I/O of 128-bit and 8-bit integers
 *      - Handling the evilness of SeedSeq
 *      - Support for efficiently producing random numbers less than a given
 *        bound
 */

#ifndef PCG_EXTRAS_HPP_INCLUDED
#define PCG_EXTRAS_HPP_INCLUDED 1

#include <cinttypes>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <limits>
#include <iostream>
#include <type_traits>
#include <utility>
#include <locale>
#include <iterator>

#ifdef __GNUC__
    #include <cxxabi.h>
#endif

/*
 * Abstractions for compiler-specific directives
 */

#ifdef __GNUC__
    #define PCG_NOINLINE __attribute__((noinline))
#else
    #define PCG_NOINLINE
#endif

/*
 * Some members of the PCG library use 128-bit math.  When compiling on 64-bit
 * platforms, both GCC and Clang provide 128-bit integer types that are ideal
 * for the job.
 *
 * On 32-bit platforms (or with other compilers), we fall back to a C++
 * class that provides 128-bit unsigned integers instead.  It may seem
 * like we're reinventing the wheel here, because libraries already exist
 * that support large integers, but most existing libraries provide a very
 * generic multiprecision code, but here we're operating at a fixed size.
 * Also, most other libraries are fairly heavyweight.  So we use a direct
 * implementation.  Sadly, it's much slower than hand-coded assembly or
 * direct CPU support.
 *
 */
#if __SIZEOF_INT128__
    namespace pcg_extras {
        typedef __uint128_t pcg128_t;
    }
    #define PCG_128BIT_CONSTANT(high,low) \
            ((pcg_extras::pcg128_t(high) << 64) + low)
#else


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #5
// See the end of this file for a list

/*
 * PCG Random Number Generation for C++
 *
 * Copyright 2014-2017 Melissa O'Neill <oneill@pcg-random.org>,
 *                     and the PCG Project contributors.
 *
 * SPDX-License-Identifier: (Apache-2.0 OR MIT)
 *
 * Licensed under the Apache License, Version 2.0 (provided in
 * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0)
 * or under the MIT license (provided in LICENSE-MIT.txt and at
 * http://opensource.org/licenses/MIT), at your option. This file may not
 * be copied, modified, or distributed except according to those terms.
 *
 * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either
 * express or implied.  See your chosen license for details.
 *
 * For additional information about the PCG random number generation scheme,
 * visit http://www.pcg-random.org/.
 */

/*
 * This code provides a a C++ class that can provide 128-bit (or higher)
 * integers.  To produce 2K-bit integers, it uses two K-bit integers,
 * placed in a union that allowes the code to also see them as four K/2 bit
 * integers (and access them either directly name, or by index).
 *
 * It may seem like we're reinventing the wheel here, because several
 * libraries already exist that support large integers, but most existing
 * libraries provide a very generic multiprecision code, but here we're
 * operating at a fixed size.  Also, most other libraries are fairly
 * heavyweight.  So we use a direct implementation.  Sadly, it's much slower
 * than hand-coded assembly or direct CPU support.
 */

#ifndef PCG_UINT128_HPP_INCLUDED
#define PCG_UINT128_HPP_INCLUDED 1

#include <cstdint>
#include <cstdio>
#include <cassert>
#include <climits>
#include <utility>
#include <initializer_list>
#include <type_traits>

#if defined(_MSC_VER)  // Use MSVC++ intrinsics
#include <intrin.h>
#endif

/*
 * We want to lay the type out the same way that a native type would be laid
 * out, which means we must know the machine's endian, at compile time.
 * This ugliness attempts to do so.
 */

#ifndef PCG_LITTLE_ENDIAN
    #if defined(__BYTE_ORDER__)
        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
            #define PCG_LITTLE_ENDIAN 1
        #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
            #define PCG_LITTLE_ENDIAN 0
        #else
            #error __BYTE_ORDER__ does not match a standard endian, pick a side
        #endif
    #elif __LITTLE_ENDIAN__ || _LITTLE_ENDIAN
        #define PCG_LITTLE_ENDIAN 1
    #elif __BIG_ENDIAN__ || _BIG_ENDIAN
        #define PCG_LITTLE_ENDIAN 0
    #elif __x86_64 || __x86_64__ || _M_X64 || __i386 || __i386__ || _M_IX86
        #define PCG_LITTLE_ENDIAN 1
    #elif __powerpc__ || __POWERPC__ || __ppc__ || __PPC__ \
          || __m68k__ || __mc68000__
        #define PCG_LITTLE_ENDIAN 0
    #else
        #error Unable to determine target endianness
    #endif
#endif

namespace pcg_extras {

// Recent versions of GCC have intrinsics we can use to quickly calculate
// the number of leading and trailing zeros in a number.  If possible, we
// use them, otherwise we fall back to old-fashioned bit twiddling to figure
// them out.

#ifndef PCG_BITCOUNT_T
    typedef uint8_t bitcount_t;
#else
    typedef PCG_BITCOUNT_T bitcount_t;
#endif

/*
 * Provide some useful helper functions
 *      * flog2                 floor(log2(x))
 *      * trailingzeros         number of trailing zero bits
 */

#if defined(__GNUC__)   // Any GNU-compatible compiler supporting C++11 has
                        // some useful intrinsics we can use.

inline bitcount_t flog2(uint32_t v)
{
    return 31 - __builtin_clz(v);
}

inline bitcount_t trailingzeros(uint32_t v)
{
    return __builtin_ctz(v);
}

inline bitcount_t flog2(uint64_t v)
{
#if UINT64_MAX == ULONG_MAX
    return 63 - __builtin_clzl(v);
#elif UINT64_MAX == ULLONG_MAX
    return 63 - __builtin_clzll(v);
#else
    #error Cannot find a function for uint64_t
#endif
}

inline bitcount_t trailingzeros(uint64_t v)
{
#if UINT64_MAX == ULONG_MAX
    return __builtin_ctzl(v);
#elif UINT64_MAX == ULLONG_MAX
    return __builtin_ctzll(v);
#else
    #error Cannot find a function for uint64_t
#endif
}

#elif defined(_MSC_VER)  // Use MSVC++ intrinsics

#pragma intrinsic(_BitScanReverse, _BitScanForward)
#if defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64)
#pragma intrinsic(_BitScanReverse64, _BitScanForward64)
#endif

inline bitcount_t flog2(uint32_t v)
{
    unsigned long i;
    _BitScanReverse(&i, v);
    return bitcount_t(i);
}

inline bitcount_t trailingzeros(uint32_t v)
{
    unsigned long i;
    _BitScanForward(&i, v);
    return bitcount_t(i);
}

inline bitcount_t flog2(uint64_t v)
{
#if defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64)
    unsigned long i;
    _BitScanReverse64(&i, v);
    return bitcount_t(i);
#else
    // 32-bit x86
    uint32_t high = v >> 32;
    uint32_t low  = uint32_t(v);
    return high ? 32+flog2(high) : flog2(low);
#endif
}

inline bitcount_t trailingzeros(uint64_t v)
{
#if defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64)
    unsigned long i;
    _BitScanForward64(&i, v);
    return bitcount_t(i);
#else
    // 32-bit x86
    uint32_t high = v >> 32;
    uint32_t low  = uint32_t(v);
    return low ? trailingzeros(low) : trailingzeros(high)+32;
#endif
}

#else                   // Otherwise, we fall back to bit twiddling
                        // implementations

inline bitcount_t flog2(uint32_t v)
{
    // Based on code by Eric Cole and Mark Dickinson, which appears at
    // https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn

    static const uint8_t multiplyDeBruijnBitPos[32] = {
      0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
      8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
    };

    v |= v >> 1; // first round down to one less than a power of 2
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;

    return multiplyDeBruijnBitPos[(uint32_t)(v * 0x07C4ACDDU) >> 27];
}

inline bitcount_t trailingzeros(uint32_t v)
{
    static const uint8_t multiplyDeBruijnBitPos[32] = {
      0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
    };

    return multiplyDeBruijnBitPos[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];
}

inline bitcount_t flog2(uint64_t v)
{
    uint32_t high = v >> 32;
    uint32_t low  = uint32_t(v);

    return high ? 32+flog2(high) : flog2(low);
}

inline bitcount_t trailingzeros(uint64_t v)
{
    uint32_t high = v >> 32;
    uint32_t low  = uint32_t(v);

    return low ? trailingzeros(low) : trailingzeros(high)+32;
}

#endif

inline bitcount_t flog2(uint8_t v)
{
    return flog2(uint32_t(v));
}

inline bitcount_t flog2(uint16_t v)
{
    return flog2(uint32_t(v));
}

#if __SIZEOF_INT128__
inline bitcount_t flog2(__uint128_t v)
{
    uint64_t high = uint64_t(v >> 64);
    uint64_t low  = uint64_t(v);

    return high ? 64+flog2(high) : flog2(low);
}
#endif

inline bitcount_t trailingzeros(uint8_t v)
{
    return trailingzeros(uint32_t(v));
}

inline bitcount_t trailingzeros(uint16_t v)
{
    return trailingzeros(uint32_t(v));
}

#if __SIZEOF_INT128__
inline bitcount_t trailingzeros(__uint128_t v)
{
    uint64_t high = uint64_t(v >> 64);
    uint64_t low  = uint64_t(v);
    return low ? trailingzeros(low) : trailingzeros(high)+64;
}
#endif

template <typename UInt>
inline bitcount_t clog2(UInt v)
{
    return flog2(v) + ((v & (-v)) != v);
}

template <typename UInt>
inline UInt addwithcarry(UInt x, UInt y, bool carryin, bool* carryout)
{
    UInt half_result = y + carryin;
    UInt result = x + half_result;
    *carryout = (half_result < y) || (result < x);
    return result;
}

template <typename UInt>
inline UInt subwithcarry(UInt x, UInt y, bool carryin, bool* carryout)
{
    UInt half_result = y + carryin;
    UInt result = x - half_result;
    *carryout = (half_result < y) || (result > x);
    return result;
}


template <typename UInt, typename UIntX2>
class uint_x4 {
// private:
    static constexpr unsigned int UINT_BITS = sizeof(UInt) * CHAR_BIT;
public:
    union {
#if PCG_LITTLE_ENDIAN
        struct {
            UInt v0, v1, v2, v3;
        } w;
        struct {
            UIntX2 v01, v23;
        } d;
#else
        struct {
            UInt v3, v2, v1, v0;
        } w;
        struct {
            UIntX2 v23, v01;
        } d;
#endif
        // For the array access versions, the code that uses the array
        // must handle endian itself.  Yuck.
        UInt wa[4];
        UIntX2 da[2];
    };

public:
    uint_x4() = default;

    constexpr uint_x4(UInt v3, UInt v2, UInt v1, UInt v0)
#if PCG_LITTLE_ENDIAN
       : w{v0, v1, v2, v3}
#else
       : w{v3, v2, v1, v0}
#endif
    {
        // Nothing (else) to do
    }

    constexpr uint_x4(UIntX2 v23, UIntX2 v01)
#if PCG_LITTLE_ENDIAN
       : d{v01,v23}
#else
       : d{v23,v01}
#endif
    {
        // Nothing (else) to do
    }

    constexpr uint_x4(UIntX2 v01)
#if PCG_LITTLE_ENDIAN
       : d{v01, UIntX2(0)}
#else
       : d{UIntX2(0),v01}
#endif
    {
        // Nothing (else) to do
    }

    template<class Integral,
             typename std::enable_if<(std::is_integral<Integral>::value
                                      && sizeof(Integral) <= sizeof(UIntX2))
                                    >::type* = nullptr>
    constexpr uint_x4(Integral v01)
#if PCG_LITTLE_ENDIAN
       : d{UIntX2(v01), UIntX2(0)}
#else
       : d{UIntX2(0), UIntX2(v01)}
#endif
    {
        // Nothing (else) to do
    }

    explicit constexpr operator UIntX2() const
    {
        return d.v01;
    }

    template<class Integral,
             typename std::enable_if<(std::is_integral<Integral>::value
                                      && sizeof(Integral) <= sizeof(UIntX2))
                                    >::type* = nullptr>
    explicit constexpr operator Integral() const
    {
        return Integral(d.v01);
    }

    explicit constexpr operator bool() const
    {
        return d.v01 || d.v23;
    }

    template<typename U, typename V>
    friend uint_x4<U,V> operator*(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator*(const uint_x4<U,V>&, V);

    template<typename U, typename V>
    friend std::pair< uint_x4<U,V>,uint_x4<U,V> >
        divmod(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator+(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator-(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator<<(const uint_x4<U,V>&, const bitcount_t shift);

    template<typename U, typename V>
    friend uint_x4<U,V> operator>>(const uint_x4<U,V>&, const bitcount_t shift);

    template<typename U, typename V>
    friend uint_x4<U,V> operator&(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator|(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator^(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bool operator==(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bool operator!=(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bool operator<(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bool operator<=(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bool operator>(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bool operator>=(const uint_x4<U,V>&, const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator~(const uint_x4<U,V>&);

    template<typename U, typename V>
    friend uint_x4<U,V> operator-(const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bitcount_t flog2(const uint_x4<U,V>&);

    template<typename U, typename V>
    friend bitcount_t trailingzeros(const uint_x4<U,V>&);

    uint_x4& operator*=(const uint_x4& rhs)
    {
        uint_x4 result = *this * rhs;
        return *this = result;
    }

    uint_x4& operator*=(UIntX2 rhs)
    {
        uint_x4 result = *this * rhs;
        return *this = result;
    }

    uint_x4& operator/=(const uint_x4& rhs)
    {
        uint_x4 result = *this / rhs;
        return *this = result;
    }

    uint_x4& operator%=(const uint_x4& rhs)
    {
        uint_x4 result = *this % rhs;
        return *this = result;
    }

    uint_x4& operator+=(const uint_x4& rhs)
    {
        uint_x4 result = *this + rhs;
        return *this = result;
    }

    uint_x4& operator-=(const uint_x4& rhs)
    {
        uint_x4 result = *this - rhs;
        return *this = result;
    }

    uint_x4& operator&=(const uint_x4& rhs)
    {
        uint_x4 result = *this & rhs;
        return *this = result;
    }

    uint_x4& operator|=(const uint_x4& rhs)
    {
        uint_x4 result = *this | rhs;
        return *this = result;
    }

    uint_x4& operator^=(const uint_x4& rhs)
    {
        uint_x4 result = *this ^ rhs;
        return *this = result;
    }

    uint_x4& operator>>=(bitcount_t shift)
    {
        uint_x4 result = *this >> shift;
        return *this = result;
    }

    uint_x4& operator<<=(bitcount_t shift)
    {
        uint_x4 result = *this << shift;
        return *this = result;
    }

};

template<typename U, typename V>
bitcount_t flog2(const uint_x4<U,V>& v)
{
#if PCG_LITTLE_ENDIAN
    for (uint8_t i = 4; i !=0; /* dec in loop */) {
        --i;
#else
    for (uint8_t i = 0; i < 4; ++i) {
#endif
        if (v.wa[i] == 0)
             continue;
        return flog2(v.wa[i]) + uint_x4<U,V>::UINT_BITS*i;
    }
    abort();
}

template<typename U, typename V>
bitcount_t trailingzeros(const uint_x4<U,V>& v)
{
#if PCG_LITTLE_ENDIAN
    for (uint8_t i = 0; i < 4; ++i) {
#else
    for (uint8_t i = 4; i !=0; /* dec in loop */) {
        --i;
#endif
        if (v.wa[i] != 0)
            return trailingzeros(v.wa[i]) + uint_x4<U,V>::UINT_BITS*i;
    }
    return uint_x4<U,V>::UINT_BITS*4;
}

template <typename UInt, typename UIntX2>
std::pair< uint_x4<UInt,UIntX2>, uint_x4<UInt,UIntX2> >
    divmod(const uint_x4<UInt,UIntX2>& orig_dividend,
           const uint_x4<UInt,UIntX2>& divisor)
{
    // If the dividend is less than the divisor, the answer is always zero.
    // This takes care of boundary cases like 0/x (which would otherwise be
    // problematic because we can't take the log of zero.  (The boundary case
    // of division by zero is undefined.)
    if (orig_dividend < divisor)
        return { uint_x4<UInt,UIntX2>(UIntX2(0)), orig_dividend };

    auto dividend = orig_dividend;

    auto log2_divisor  = flog2(divisor);
    auto log2_dividend = flog2(dividend);
    // assert(log2_dividend >= log2_divisor);
    bitcount_t logdiff = log2_dividend - log2_divisor;

    constexpr uint_x4<UInt,UIntX2> ONE(UIntX2(1));
    if (logdiff == 0)
        return { ONE, dividend - divisor };

    // Now we change the log difference to
    //  floor(log2(divisor)) - ceil(log2(dividend))
    // to ensure that we *underestimate* the result.
    logdiff -= 1;

    uint_x4<UInt,UIntX2> quotient(UIntX2(0));

    auto qfactor = ONE << logdiff;
    auto factor  = divisor << logdiff;

    do {
        dividend -= factor;
        quotient += qfactor;
        while (dividend < factor) {
            factor  >>= 1;
            qfactor >>= 1;
        }
    } while (dividend >= divisor);

    return { quotient, dividend };
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator/(const uint_x4<UInt,UIntX2>& dividend,
                               const uint_x4<UInt,UIntX2>& divisor)
{
    return divmod(dividend, divisor).first;
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator%(const uint_x4<UInt,UIntX2>& dividend,
                               const uint_x4<UInt,UIntX2>& divisor)
{
    return divmod(dividend, divisor).second;
}


template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator*(const uint_x4<UInt,UIntX2>& a,
                               const uint_x4<UInt,UIntX2>& b)
{
    constexpr auto UINT_BITS = uint_x4<UInt,UIntX2>::UINT_BITS;
    uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
    bool carryin = false;
    bool carryout;
    UIntX2 a0b0 = UIntX2(a.w.v0) * UIntX2(b.w.v0);
    r.w.v0 = UInt(a0b0);
    r.w.v1 = UInt(a0b0 >> UINT_BITS);

    UIntX2 a1b0 = UIntX2(a.w.v1) * UIntX2(b.w.v0);
    r.w.v2 = UInt(a1b0 >> UINT_BITS);
    r.w.v1 = addwithcarry(r.w.v1, UInt(a1b0), carryin, &carryout);
    carryin = carryout;
    r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);

    UIntX2 a0b1 = UIntX2(a.w.v0) * UIntX2(b.w.v1);
    carryin = false;
    r.w.v2 = addwithcarry(r.w.v2, UInt(a0b1 >> UINT_BITS), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);

    carryin = false;
    r.w.v1 = addwithcarry(r.w.v1, UInt(a0b1), carryin, &carryout);
    carryin = carryout;
    r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);

    UIntX2 a1b1 = UIntX2(a.w.v1) * UIntX2(b.w.v1);
    carryin = false;
    r.w.v2 = addwithcarry(r.w.v2, UInt(a1b1), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(a1b1 >> UINT_BITS), carryin, &carryout);

    r.d.v23 += a.d.v01 * b.d.v23 + a.d.v23 * b.d.v01;

    return r;
}


template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator*(const uint_x4<UInt,UIntX2>& a,
                               UIntX2 b01)
{
    constexpr auto UINT_BITS = uint_x4<UInt,UIntX2>::UINT_BITS;
    uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
    bool carryin = false;
    bool carryout;
    UIntX2 a0b0 = UIntX2(a.w.v0) * UIntX2(UInt(b01));
    r.w.v0 = UInt(a0b0);
    r.w.v1 = UInt(a0b0 >> UINT_BITS);

    UIntX2 a1b0 = UIntX2(a.w.v1) * UIntX2(UInt(b01));
    r.w.v2 = UInt(a1b0 >> UINT_BITS);
    r.w.v1 = addwithcarry(r.w.v1, UInt(a1b0), carryin, &carryout);
    carryin = carryout;
    r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);

    UIntX2 a0b1 = UIntX2(a.w.v0) * UIntX2(b01 >> UINT_BITS);
    carryin = false;
    r.w.v2 = addwithcarry(r.w.v2, UInt(a0b1 >> UINT_BITS), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);

    carryin = false;
    r.w.v1 = addwithcarry(r.w.v1, UInt(a0b1), carryin, &carryout);
    carryin = carryout;
    r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);

    UIntX2 a1b1 = UIntX2(a.w.v1) * UIntX2(b01 >> UINT_BITS);
    carryin = false;
    r.w.v2 = addwithcarry(r.w.v2, UInt(a1b1), carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(r.w.v3, UInt(a1b1 >> UINT_BITS), carryin, &carryout);

    r.d.v23 += a.d.v23 * b01;

    return r;
}


template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator+(const uint_x4<UInt,UIntX2>& a,
                               const uint_x4<UInt,UIntX2>& b)
{
    uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};

    bool carryin = false;
    bool carryout;
    r.w.v0 = addwithcarry(a.w.v0, b.w.v0, carryin, &carryout);
    carryin = carryout;
    r.w.v1 = addwithcarry(a.w.v1, b.w.v1, carryin, &carryout);
    carryin = carryout;
    r.w.v2 = addwithcarry(a.w.v2, b.w.v2, carryin, &carryout);
    carryin = carryout;
    r.w.v3 = addwithcarry(a.w.v3, b.w.v3, carryin, &carryout);

    return r;
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator-(const uint_x4<UInt,UIntX2>& a,
                               const uint_x4<UInt,UIntX2>& b)
{
    uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};

    bool carryin = false;
    bool carryout;
    r.w.v0 = subwithcarry(a.w.v0, b.w.v0, carryin, &carryout);
    carryin = carryout;
    r.w.v1 = subwithcarry(a.w.v1, b.w.v1, carryin, &carryout);
    carryin = carryout;
    r.w.v2 = subwithcarry(a.w.v2, b.w.v2, carryin, &carryout);
    carryin = carryout;
    r.w.v3 = subwithcarry(a.w.v3, b.w.v3, carryin, &carryout);

    return r;
}


template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator&(const uint_x4<UInt,UIntX2>& a,
                               const uint_x4<UInt,UIntX2>& b)
{
    return uint_x4<UInt,UIntX2>(a.d.v23 & b.d.v23, a.d.v01 & b.d.v01);
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator|(const uint_x4<UInt,UIntX2>& a,
                               const uint_x4<UInt,UIntX2>& b)
{
    return uint_x4<UInt,UIntX2>(a.d.v23 | b.d.v23, a.d.v01 | b.d.v01);
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator^(const uint_x4<UInt,UIntX2>& a,
                               const uint_x4<UInt,UIntX2>& b)
{
    return uint_x4<UInt,UIntX2>(a.d.v23 ^ b.d.v23, a.d.v01 ^ b.d.v01);
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator~(const uint_x4<UInt,UIntX2>& v)
{
    return uint_x4<UInt,UIntX2>(~v.d.v23, ~v.d.v01);
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator-(const uint_x4<UInt,UIntX2>& v)
{
    return uint_x4<UInt,UIntX2>(0UL,0UL) - v;
}

template <typename UInt, typename UIntX2>
bool operator==(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
    return (a.d.v01 == b.d.v01) && (a.d.v23 == b.d.v23);
}

template <typename UInt, typename UIntX2>
bool operator!=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
    return !operator==(a,b);
}


template <typename UInt, typename UIntX2>
bool operator<(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
    return (a.d.v23 < b.d.v23)
           || ((a.d.v23 == b.d.v23) && (a.d.v01 < b.d.v01));
}

template <typename UInt, typename UIntX2>
bool operator>(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
    return operator<(b,a);
}

template <typename UInt, typename UIntX2>
bool operator<=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
    return !(operator<(b,a));
}

template <typename UInt, typename UIntX2>
bool operator>=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
    return !(operator<(a,b));
}



template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator<<(const uint_x4<UInt,UIntX2>& v,
                                const bitcount_t shift)
{
    uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
    const bitcount_t bits    = uint_x4<UInt,UIntX2>::UINT_BITS;
    const bitcount_t bitmask = bits - 1;
    const bitcount_t shiftdiv = shift / bits;
    const bitcount_t shiftmod = shift & bitmask;

    if (shiftmod) {
        UInt carryover = 0;
#if PCG_LITTLE_ENDIAN
        for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#else
        for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
            --out, --in;
#endif
            r.wa[out] = (v.wa[in] << shiftmod) | carryover;
            carryover = (v.wa[in] >> (bits - shiftmod));
        }
    } else {
#if PCG_LITTLE_ENDIAN
        for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#else
        for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
            --out, --in;
#endif
            r.wa[out] = v.wa[in];
        }
    }

    return r;
}

template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator>>(const uint_x4<UInt,UIntX2>& v,
                                const bitcount_t shift)
{
    uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
    const bitcount_t bits    = uint_x4<UInt,UIntX2>::UINT_BITS;
    const bitcount_t bitmask = bits - 1;
    const bitcount_t shiftdiv = shift / bits;
    const bitcount_t shiftmod = shift & bitmask;

    if (shiftmod) {
        UInt carryover = 0;
#if PCG_LITTLE_ENDIAN
        for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
            --out, --in;
#else
        for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#endif
            r.wa[out] = (v.wa[in] >> shiftmod) | carryover;
            carryover = (v.wa[in] << (bits - shiftmod));
        }
    } else {
#if PCG_LITTLE_ENDIAN
        for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
            --out, --in;
#else
        for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#endif
            r.wa[out] = v.wa[in];
        }
    }

    return r;
}

} // namespace pcg_extras

#endif // PCG_UINT128_HPP_INCLUDED

// LICENSE_CHANGE_END

    namespace pcg_extras {
        typedef pcg_extras::uint_x4<uint32_t,uint64_t> pcg128_t;
    }
    #define PCG_128BIT_CONSTANT(high,low) \
            pcg_extras::pcg128_t(high,low)
    #define PCG_EMULATED_128BIT_MATH 1
#endif


namespace pcg_extras {

/*
 * We often need to represent a "number of bits".  When used normally, these
 * numbers are never greater than 128, so an unsigned char is plenty.
 * If you're using a nonstandard generator of a larger size, you can set
 * PCG_BITCOUNT_T to have it define it as a larger size.  (Some compilers
 * might produce faster code if you set it to an unsigned int.)
 */

#ifndef PCG_BITCOUNT_T
    typedef uint8_t bitcount_t;
#else
    typedef PCG_BITCOUNT_T bitcount_t;
#endif

/*
 * C++ requires us to be able to serialize RNG state by printing or reading
 * it from a stream.  Because we use 128-bit ints, we also need to be able
 * ot print them, so here is code to do so.
 *
 * This code provides enough functionality to print 128-bit ints in decimal
 * and zero-padded in hex.  It's not a full-featured implementation.
 */

template <typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>& out, pcg128_t value)
{
    auto desired_base = out.flags() & out.basefield;
    bool want_hex = desired_base == out.hex;

    if (want_hex) {
        uint64_t highpart = uint64_t(value >> 64);
        uint64_t lowpart  = uint64_t(value);
        auto desired_width = out.width();
        if (desired_width > 16) {
            out.width(desired_width - 16);
        }
        if (highpart != 0 || desired_width > 16)
            out << highpart;
        CharT oldfill = '\0';
        if (highpart != 0) {
            out.width(16);
            oldfill = out.fill('0');
        }
        auto oldflags = out.setf(decltype(desired_base){}, out.showbase);
        out << lowpart;
        out.setf(oldflags);
        if (highpart != 0) {
            out.fill(oldfill);
        }
        return out;
    }
    constexpr size_t MAX_CHARS_128BIT = 40;

    char buffer[MAX_CHARS_128BIT];
    char* pos = buffer+sizeof(buffer);
    *(--pos) = '\0';
    constexpr auto BASE = pcg128_t(10ULL);
    do {
        auto div = value / BASE;
        auto mod = uint32_t(value - (div * BASE));
        *(--pos) = '0' + char(mod);
        value = div;
    } while(value != pcg128_t(0ULL));
    return out << pos;
}

template <typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in, pcg128_t& value)
{
    typename std::basic_istream<CharT,Traits>::sentry s(in);

    if (!s)
         return in;

    constexpr auto BASE = pcg128_t(10ULL);
    pcg128_t current(0ULL);
    bool did_nothing = true;
    bool overflow = false;
    for(;;) {
        CharT wide_ch = in.get();
        if (!in.good())
            break;
        auto ch = in.narrow(wide_ch, '\0');
        if (ch < '0' || ch > '9') {
            in.unget();
            break;
        }
        did_nothing = false;
        pcg128_t digit(uint32_t(ch - '0'));
        pcg128_t timesbase = current*BASE;
        overflow = overflow || timesbase < current;
        current = timesbase + digit;
        overflow = overflow || current < digit;
    }

    if (did_nothing || overflow) {
        in.setstate(std::ios::failbit);
        if (overflow)
            current = ~pcg128_t(0ULL);
    }

    value = current;

    return in;
}

/*
 * Likewise, if people use tiny rngs, we'll be serializing uint8_t.
 * If we just used the provided IO operators, they'd read/write chars,
 * not ints, so we need to define our own.  We *can* redefine this operator
 * here because we're in our own namespace.
 */

template <typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>&out, uint8_t value)
{
    return out << uint32_t(value);
}

template <typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in, uint8_t& target)
{
    uint32_t value = 0xdecea5edU;
    in >> value;
    if (!in && value == 0xdecea5edU)
        return in;
    if (value > uint8_t(~0)) {
        in.setstate(std::ios::failbit);
        value = ~0U;
    }
    target = uint8_t(value);
    return in;
}

/* Unfortunately, the above functions don't get found in preference to the
 * built in ones, so we create some more specific overloads that will.
 * Ugh.
 */

inline std::ostream& operator<<(std::ostream& out, uint8_t value)
{
    return pcg_extras::operator<< <char>(out, value);
}

inline std::istream& operator>>(std::istream& in, uint8_t& value)
{
    return pcg_extras::operator>> <char>(in, value);
}



/*
 * Useful bitwise operations.
 */

/*
 * XorShifts are invertable, but they are someting of a pain to invert.
 * This function backs them out.  It's used by the whacky "inside out"
 * generator defined later.
 */

template <typename itype>
inline itype unxorshift(itype x, bitcount_t bits, bitcount_t shift)
{
    if (2*shift >= bits) {
        return x ^ (x >> shift);
    }
    itype lowmask1 = (itype(1U) << (bits - shift*2)) - 1;
    itype highmask1 = ~lowmask1;
    itype top1 = x;
    itype bottom1 = x & lowmask1;
    top1 ^= top1 >> shift;
    top1 &= highmask1;
    x = top1 | bottom1;
    itype lowmask2 = (itype(1U) << (bits - shift)) - 1;
    itype bottom2 = x & lowmask2;
    bottom2 = unxorshift(bottom2, bits - shift, shift);
    bottom2 &= lowmask1;
    return top1 | bottom2;
}

/*
 * Rotate left and right.
 *
 * In ideal world, compilers would spot idiomatic rotate code and convert it
 * to a rotate instruction.  Of course, opinions vary on what the correct
 * idiom is and how to spot it.  For clang, sometimes it generates better
 * (but still crappy) code if you define PCG_USE_ZEROCHECK_ROTATE_IDIOM.
 */

template <typename itype>
inline itype rotl(itype value, bitcount_t rot)
{
    constexpr bitcount_t bits = sizeof(itype) * 8;
    constexpr bitcount_t mask = bits - 1;
#if PCG_USE_ZEROCHECK_ROTATE_IDIOM
    return rot ? (value << rot) | (value >> (bits - rot)) : value;
#else
    return (value << rot) | (value >> ((- rot) & mask));
#endif
}

template <typename itype>
inline itype rotr(itype value, bitcount_t rot)
{
    constexpr bitcount_t bits = sizeof(itype) * 8;
    constexpr bitcount_t mask = bits - 1;
#if PCG_USE_ZEROCHECK_ROTATE_IDIOM
    return rot ? (value >> rot) | (value << (bits - rot)) : value;
#else
    return (value >> rot) | (value << ((- rot) & mask));
#endif
}

/* Unfortunately, both Clang and GCC sometimes perform poorly when it comes
 * to properly recognizing idiomatic rotate code, so for we also provide
 * assembler directives (enabled with PCG_USE_INLINE_ASM).  Boo, hiss.
 * (I hope that these compilers get better so that this code can die.)
 *
 * These overloads will be preferred over the general template code above.
 */
#if PCG_USE_INLINE_ASM && __GNUC__ && (__x86_64__  || __i386__)

inline uint8_t rotr(uint8_t value, bitcount_t rot)
{
    asm ("rorb   %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
    return value;
}

inline uint16_t rotr(uint16_t value, bitcount_t rot)
{
    asm ("rorw   %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
    return value;
}

inline uint32_t rotr(uint32_t value, bitcount_t rot)
{
    asm ("rorl   %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
    return value;
}

#if __x86_64__
inline uint64_t rotr(uint64_t value, bitcount_t rot)
{
    asm ("rorq   %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
    return value;
}
#endif // __x86_64__

#elif defined(_MSC_VER)
  // Use MSVC++ bit rotation intrinsics

#pragma intrinsic(_rotr, _rotr64, _rotr8, _rotr16)

inline uint8_t rotr(uint8_t value, bitcount_t rot)
{
    return _rotr8(value, rot);
}

inline uint16_t rotr(uint16_t value, bitcount_t rot)
{
    return _rotr16(value, rot);
}

inline uint32_t rotr(uint32_t value, bitcount_t rot)
{
    return _rotr(value, rot);
}

inline uint64_t rotr(uint64_t value, bitcount_t rot)
{
    return _rotr64(value, rot);
}

#endif // PCG_USE_INLINE_ASM


/*
 * The C++ SeedSeq concept (modelled by seed_seq) can fill an array of
 * 32-bit integers with seed data, but sometimes we want to produce
 * larger or smaller integers.
 *
 * The following code handles this annoyance.
 *
 * uneven_copy will copy an array of 32-bit ints to an array of larger or
 * smaller ints (actually, the code is general it only needing forward
 * iterators).  The copy is identical to the one that would be performed if
 * we just did memcpy on a standard little-endian machine, but works
 * regardless of the endian of the machine (or the weirdness of the ints
 * involved).
 *
 * generate_to initializes an array of integers using a SeedSeq
 * object.  It is given the size as a static constant at compile time and
 * tries to avoid memory allocation.  If we're filling in 32-bit constants
 * we just do it directly.  If we need a separate buffer and it's small,
 * we allocate it on the stack.  Otherwise, we fall back to heap allocation.
 * Ugh.
 *
 * generate_one produces a single value of some integral type using a
 * SeedSeq object.
 */

 /* uneven_copy helper, case where destination ints are less than 32 bit. */

template<class SrcIter, class DestIter>
SrcIter uneven_copy_impl(
    SrcIter src_first, DestIter dest_first, DestIter dest_last,
    std::true_type)
{
    typedef typename std::iterator_traits<SrcIter>::value_type  src_t;
    typedef typename std::iterator_traits<DestIter>::value_type dest_t;

    constexpr bitcount_t SRC_SIZE  = sizeof(src_t);
    constexpr bitcount_t DEST_SIZE = sizeof(dest_t);
    constexpr bitcount_t DEST_BITS = DEST_SIZE * 8;
    constexpr bitcount_t SCALE     = SRC_SIZE / DEST_SIZE;

    size_t count = 0;
    src_t value = 0;

    while (dest_first != dest_last) {
        if ((count++ % SCALE) == 0)
            value = *src_first++;       // Get more bits
        else
            value >>= DEST_BITS;        // Move down bits

        *dest_first++ = dest_t(value);  // Truncates, ignores high bits.
    }
    return src_first;
}

 /* uneven_copy helper, case where destination ints are more than 32 bit. */

template<class SrcIter, class DestIter>
SrcIter uneven_copy_impl(
    SrcIter src_first, DestIter dest_first, DestIter dest_last,
    std::false_type)
{
    typedef typename std::iterator_traits<SrcIter>::value_type  src_t;
    typedef typename std::iterator_traits<DestIter>::value_type dest_t;

    constexpr auto SRC_SIZE  = sizeof(src_t);
    constexpr auto SRC_BITS  = SRC_SIZE * 8;
    constexpr auto DEST_SIZE = sizeof(dest_t);
    constexpr auto SCALE     = (DEST_SIZE+SRC_SIZE-1) / SRC_SIZE;

    while (dest_first != dest_last) {
        dest_t value(0UL);
        unsigned int shift = 0;

        for (size_t i = 0; i < SCALE; ++i) {
            value |= dest_t(*src_first++) << shift;
            shift += SRC_BITS;
        }

        *dest_first++ = value;
    }
    return src_first;
}

/* uneven_copy, call the right code for larger vs. smaller */

template<class SrcIter, class DestIter>
inline SrcIter uneven_copy(SrcIter src_first,
                           DestIter dest_first, DestIter dest_last)
{
    typedef typename std::iterator_traits<SrcIter>::value_type  src_t;
    typedef typename std::iterator_traits<DestIter>::value_type dest_t;

    constexpr bool DEST_IS_SMALLER = sizeof(dest_t) < sizeof(src_t);

    return uneven_copy_impl(src_first, dest_first, dest_last,
                            std::integral_constant<bool, DEST_IS_SMALLER>{});
}

/* generate_to, fill in a fixed-size array of integral type using a SeedSeq
 * (actually works for any random-access iterator)
 */

template <size_t size, typename SeedSeq, typename DestIter>
inline void generate_to_impl(SeedSeq&& generator, DestIter dest,
                             std::true_type)
{
    generator.generate(dest, dest+size);
}

template <size_t size, typename SeedSeq, typename DestIter>
void generate_to_impl(SeedSeq&& generator, DestIter dest,
                      std::false_type)
{
    typedef typename std::iterator_traits<DestIter>::value_type dest_t;
    constexpr auto DEST_SIZE = sizeof(dest_t);
    constexpr auto GEN_SIZE  = sizeof(uint32_t);

    constexpr bool GEN_IS_SMALLER = GEN_SIZE < DEST_SIZE;
    constexpr size_t FROM_ELEMS =
        GEN_IS_SMALLER
            ? size * ((DEST_SIZE+GEN_SIZE-1) / GEN_SIZE)
            : (size + (GEN_SIZE / DEST_SIZE) - 1)
                / ((GEN_SIZE / DEST_SIZE) + GEN_IS_SMALLER);
                        //  this odd code ^^^^^^^^^^^^^^^^^ is work-around for
                        //  a bug: http://llvm.org/bugs/show_bug.cgi?id=21287

    if (FROM_ELEMS <= 1024) {
        uint32_t buffer[FROM_ELEMS];
        generator.generate(buffer, buffer+FROM_ELEMS);
        uneven_copy(buffer, dest, dest+size);
    } else {
        uint32_t* buffer = static_cast<uint32_t*>(malloc(GEN_SIZE * FROM_ELEMS));
        generator.generate(buffer, buffer+FROM_ELEMS);
        uneven_copy(buffer, dest, dest+size);
        free(static_cast<void*>(buffer));
    }
}

template <size_t size, typename SeedSeq, typename DestIter>
inline void generate_to(SeedSeq&& generator, DestIter dest)
{
    typedef typename std::iterator_traits<DestIter>::value_type dest_t;
    constexpr bool IS_32BIT = sizeof(dest_t) == sizeof(uint32_t);

    generate_to_impl<size>(std::forward<SeedSeq>(generator), dest,
                           std::integral_constant<bool, IS_32BIT>{});
}

/* generate_one, produce a value of integral type using a SeedSeq
 * (optionally, we can have it produce more than one and pick which one
 * we want)
 */

template <typename UInt, size_t i = 0UL, size_t N = i+1UL, typename SeedSeq>
inline UInt generate_one(SeedSeq&& generator)
{
    UInt result[N];
    generate_to<N>(std::forward<SeedSeq>(generator), result);
    return result[i];
}

template <typename RngType>
auto bounded_rand(RngType& rng, typename RngType::result_type upper_bound)
        -> typename RngType::result_type
{
    typedef typename RngType::result_type rtype;
    rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound)
                    % upper_bound;
    for (;;) {
        rtype r = rng() - RngType::min();
        if (r >= threshold)
            return r % upper_bound;
    }
}

template <typename Iter, typename RandType>
void shuffle(Iter from, Iter to, RandType&& rng)
{
    typedef typename std::iterator_traits<Iter>::difference_type delta_t;
    typedef typename std::remove_reference<RandType>::type::result_type result_t;
    auto count = to - from;
    while (count > 1) {
        delta_t chosen = delta_t(bounded_rand(rng, result_t(count)));
        --count;
        --to;
        using std::swap;
        swap(*(from + chosen), *to);
    }
}

/*
 * Although std::seed_seq is useful, it isn't everything.  Often we want to
 * initialize a random-number generator some other way, such as from a random
 * device.
 *
 * Technically, it does not meet the requirements of a SeedSequence because
 * it lacks some of the rarely-used member functions (some of which would
 * be impossible to provide).  However the C++ standard is quite specific
 * that actual engines only called the generate method, so it ought not to be
 * a problem in practice.
 */

template <typename RngType>
class seed_seq_from {
private:
    RngType rng_;

    typedef uint_least32_t result_type;

public:
    template<typename... Args>
    seed_seq_from(Args&&... args) :
        rng_(std::forward<Args>(args)...)
    {
        // Nothing (else) to do...
    }

    template<typename Iter>
    void generate(Iter start, Iter finish)
    {
        for (auto i = start; i != finish; ++i)
            *i = result_type(rng_());
    }

    constexpr size_t size() const
    {
        return (sizeof(typename RngType::result_type) > sizeof(result_type)
                && RngType::max() > ~size_t(0UL))
             ? ~size_t(0UL)
             : size_t(RngType::max());
    }
};

/*
 * Sometimes you might want a distinct seed based on when the program
 * was compiled.  That way, a particular instance of the program will
 * behave the same way, but when recompiled it'll produce a different
 * value.
 */

template <typename IntType>
struct static_arbitrary_seed {
private:
    static constexpr IntType fnv(IntType hash, const char* pos) {
        return *pos == '\0'
             ? hash
             : fnv((hash * IntType(16777619U)) ^ *pos, (pos+1));
    }

public:
    static constexpr IntType value = fnv(IntType(2166136261U ^ sizeof(IntType)),
                        __DATE__ __TIME__ __FILE__);
};

// Sometimes, when debugging or testing, it's handy to be able print the name
// of a (in human-readable form).  This code allows the idiom:
//
//      cout << printable_typename<my_foo_type_t>()
//
// to print out my_foo_type_t (or its concrete type if it is a synonym)

#if __cpp_rtti || __GXX_RTTI

template <typename T>
struct printable_typename {};

template <typename T>
std::ostream& operator<<(std::ostream& out, printable_typename<T>) {
    const char *implementation_typename = typeid(T).name();
#ifdef __GNUC__
    int status;
    char* pretty_name =
        abi::__cxa_demangle(implementation_typename, nullptr, nullptr, &status);
    if (status == 0)
        out << pretty_name;
    free(static_cast<void*>(pretty_name));
    if (status == 0)
        return out;
#endif
    out << implementation_typename;
    return out;
}

#endif  // __cpp_rtti || __GXX_RTTI

} // namespace pcg_extras

#endif // PCG_EXTRAS_HPP_INCLUDED

// LICENSE_CHANGE_END


namespace pcg_detail {

using namespace pcg_extras;

/*
 * The LCG generators need some constants to function.  This code lets you
 * look up the constant by *type*.  For example
 *
 *      default_multiplier<uint32_t>::multiplier()
 *
 * gives you the default multipler for 32-bit integers.  We use the name
 * of the constant and not a generic word like value to allow these classes
 * to be used as mixins.
 */

template <typename T>
struct default_multiplier {
    // Not defined for an arbitrary type
};

template <typename T>
struct default_increment {
    // Not defined for an arbitrary type
};

#define PCG_DEFINE_CONSTANT(type, what, kind, constant) \
        template <>                                     \
        struct what ## _ ## kind<type> {                \
            static constexpr type kind() {              \
                return constant;                        \
            }                                           \
        };

PCG_DEFINE_CONSTANT(uint8_t,  default, multiplier, 141U)
PCG_DEFINE_CONSTANT(uint8_t,  default, increment,  77U)

PCG_DEFINE_CONSTANT(uint16_t, default, multiplier, 12829U)
PCG_DEFINE_CONSTANT(uint16_t, default, increment,  47989U)

PCG_DEFINE_CONSTANT(uint32_t, default, multiplier, 747796405U)
PCG_DEFINE_CONSTANT(uint32_t, default, increment,  2891336453U)

PCG_DEFINE_CONSTANT(uint64_t, default, multiplier, 6364136223846793005ULL)
PCG_DEFINE_CONSTANT(uint64_t, default, increment,  1442695040888963407ULL)

PCG_DEFINE_CONSTANT(pcg128_t, default, multiplier,
        PCG_128BIT_CONSTANT(2549297995355413924ULL,4865540595714422341ULL))
PCG_DEFINE_CONSTANT(pcg128_t, default, increment,
        PCG_128BIT_CONSTANT(6364136223846793005ULL,1442695040888963407ULL))

/* Alternative (cheaper) multipliers for 128-bit */

template <typename T>
struct cheap_multiplier : public default_multiplier<T> {
    // For most types just use the default.
};

template <>
struct cheap_multiplier<pcg128_t> {
    static constexpr uint64_t multiplier() {
        return 0xda942042e4dd58b5ULL;
    }
};


/*
 * Each PCG generator is available in four variants, based on how it applies
 * the additive constant for its underlying LCG; the variations are:
 *
 *     single stream   - all instances use the same fixed constant, thus
 *                       the RNG always somewhere in same sequence
 *     mcg             - adds zero, resulting in a single stream and reduced
 *                       period
 *     specific stream - the constant can be changed at any time, selecting
 *                       a different random sequence
 *     unique stream   - the constant is based on the memory address of the
 *                       object, thus every RNG has its own unique sequence
 *
 * This variation is provided though mixin classes which define a function
 * value called increment() that returns the nesessary additive constant.
 */



/*
 * unique stream
 */


template <typename itype>
class unique_stream {
protected:
    static constexpr bool is_mcg = false;

    // Is never called, but is provided for symmetry with specific_stream
    void set_stream(...)
    {
        abort();
    }

public:
    typedef itype state_type;

    constexpr itype increment() const {
        return itype(reinterpret_cast<uintptr_t>(this) | 1);
    }

    constexpr itype stream() const
    {
         return increment() >> 1;
    }

    static constexpr bool can_specify_stream = false;

    static constexpr size_t streams_pow2()
    {
        return (sizeof(itype) < sizeof(size_t) ? sizeof(itype)
                                               : sizeof(size_t))*8 - 1u;
    }

protected:
    constexpr unique_stream() = default;
};


/*
 * no stream (mcg)
 */

template <typename itype>
class no_stream {
protected:
    static constexpr bool is_mcg = true;

    // Is never called, but is provided for symmetry with specific_stream
    void set_stream(...)
    {
        abort();
    }

public:
    typedef itype state_type;

    static constexpr itype increment() {
        return 0;
    }

    static constexpr bool can_specify_stream = false;

    static constexpr size_t streams_pow2()
    {
        return 0u;
    }

protected:
    constexpr no_stream() = default;
};


/*
 * single stream/sequence (oneseq)
 */

template <typename itype>
class oneseq_stream : public default_increment<itype> {
protected:
    static constexpr bool is_mcg = false;

    // Is never called, but is provided for symmetry with specific_stream
    void set_stream(...)
    {
        abort();
    }

public:
    typedef itype state_type;

    static constexpr itype stream()
    {
         return default_increment<itype>::increment() >> 1;
    }

    static constexpr bool can_specify_stream = false;

    static constexpr size_t streams_pow2()
    {
        return 0u;
    }

protected:
    constexpr oneseq_stream() = default;
};


/*
 * specific stream
 */

template <typename itype>
class specific_stream {
protected:
    static constexpr bool is_mcg = false;

    itype inc_ = default_increment<itype>::increment();

public:
    typedef itype state_type;
    typedef itype stream_state;

    constexpr itype increment() const {
        return inc_;
    }

    itype stream()
    {
         return inc_ >> 1;
    }

    void set_stream(itype specific_seq)
    {
         inc_ = (specific_seq << 1) | 1;
    }

    static constexpr bool can_specify_stream = true;

    static constexpr size_t streams_pow2()
    {
        return (sizeof(itype)*8) - 1u;
    }

protected:
    specific_stream() = default;

    specific_stream(itype specific_seq)
        : inc_(itype(specific_seq << 1) | itype(1U))
    {
        // Nothing (else) to do.
    }
};


/*
 * This is where it all comes together.  This function joins together three
 * mixin classes which define
 *    - the LCG additive constant (the stream)
 *    - the LCG multiplier
 *    - the output function
 * in addition, we specify the type of the LCG state, and the result type,
 * and whether to use the pre-advance version of the state for the output
 * (increasing instruction-level parallelism) or the post-advance version
 * (reducing register pressure).
 *
 * Given the high level of parameterization, the code has to use some
 * template-metaprogramming tricks to handle some of the suble variations
 * involved.
 */

template <typename xtype, typename itype,
          typename output_mixin,
          bool output_previous = true,
          typename stream_mixin = oneseq_stream<itype>,
          typename multiplier_mixin = default_multiplier<itype> >
class engine : protected output_mixin,
               public stream_mixin,
               protected multiplier_mixin {
protected:
    itype state_;

    struct can_specify_stream_tag {};
    struct no_specifiable_stream_tag {};

    using stream_mixin::increment;
    using multiplier_mixin::multiplier;

public:
    typedef xtype result_type;
    typedef itype state_type;

    static constexpr size_t period_pow2()
    {
        return sizeof(state_type)*8 - 2*stream_mixin::is_mcg;
    }

    // It would be nice to use std::numeric_limits for these, but
    // we can't be sure that it'd be defined for the 128-bit types.

    static constexpr result_type min()
    {
        return result_type(0UL);
    }

    static constexpr result_type max()
    {
        return result_type(~result_type(0UL));
    }

protected:
    itype bump(itype state)
    {
        return state * multiplier() + increment();
    }

    itype base_generate()
    {
        return state_ = bump(state_);
    }

    itype base_generate0()
    {
        itype old_state = state_;
        state_ = bump(state_);
        return old_state;
    }

public:
    result_type operator()()
    {
        if (output_previous)
            return this->output(base_generate0());
        else
            return this->output(base_generate());
    }

    result_type operator()(result_type upper_bound)
    {
        return bounded_rand(*this, upper_bound);
    }

protected:
    static itype advance(itype state, itype delta,
                         itype cur_mult, itype cur_plus);

    static itype distance(itype cur_state, itype newstate, itype cur_mult,
                          itype cur_plus, itype mask = ~itype(0U));

    itype distance(itype newstate, itype mask = itype(~itype(0U))) const
    {
        return distance(state_, newstate, multiplier(), increment(), mask);
    }

public:
    void advance(itype delta)
    {
        state_ = advance(state_, delta, this->multiplier(), this->increment());
    }

    void backstep(itype delta)
    {
        advance(-delta);
    }

    void discard(itype delta)
    {
        advance(delta);
    }

    bool wrapped()
    {
        if (stream_mixin::is_mcg) {
            // For MCGs, the low order two bits never change. In this
            // implementation, we keep them fixed at 3 to make this test
            // easier.
            return state_ == 3;
        } else {
            return state_ == 0;
        }
    }

    engine(itype state = itype(0xcafef00dd15ea5e5ULL))
        : state_(this->is_mcg ? state|state_type(3U)
                              : bump(state + this->increment()))
    {
        // Nothing else to do.
    }

    // This function may or may not exist.  It thus has to be a template
    // to use SFINAE; users don't have to worry about its template-ness.

    template <typename sm = stream_mixin>
    engine(itype state, typename sm::stream_state stream_seed)
        : stream_mixin(stream_seed),
          state_(this->is_mcg ? state|state_type(3U)
                              : bump(state + this->increment()))
    {
        // Nothing else to do.
    }

    template<typename SeedSeq>
    engine(SeedSeq&& seedSeq, typename std::enable_if<
                  !stream_mixin::can_specify_stream
               && !std::is_convertible<SeedSeq, itype>::value
               && !std::is_convertible<SeedSeq, engine>::value,
               no_specifiable_stream_tag>::type = {})
        : engine(generate_one<itype>(std::forward<SeedSeq>(seedSeq)))
    {
        // Nothing else to do.
    }

    template<typename SeedSeq>
    engine(SeedSeq&& seedSeq, typename std::enable_if<
                   stream_mixin::can_specify_stream
               && !std::is_convertible<SeedSeq, itype>::value
               && !std::is_convertible<SeedSeq, engine>::value,
        can_specify_stream_tag>::type = {})
        : engine(generate_one<itype,1,2>(seedSeq),
                 generate_one<itype,0,2>(seedSeq))
    {
        // Nothing else to do.
    }


    template<typename... Args>
    void seed(Args&&... args)
    {
        new (this) engine(std::forward<Args>(args)...);
    }

    template <typename xtype1, typename itype1,
              typename output_mixin1, bool output_previous1,
              typename stream_mixin_lhs, typename multiplier_mixin_lhs,
              typename stream_mixin_rhs, typename multiplier_mixin_rhs>
    friend bool operator==(const engine<xtype1,itype1,
                                     output_mixin1,output_previous1,
                                     stream_mixin_lhs, multiplier_mixin_lhs>&,
                           const engine<xtype1,itype1,
                                     output_mixin1,output_previous1,
                                     stream_mixin_rhs, multiplier_mixin_rhs>&);

    template <typename xtype1, typename itype1,
              typename output_mixin1, bool output_previous1,
              typename stream_mixin_lhs, typename multiplier_mixin_lhs,
              typename stream_mixin_rhs, typename multiplier_mixin_rhs>
    friend itype1 operator-(const engine<xtype1,itype1,
                                     output_mixin1,output_previous1,
                                     stream_mixin_lhs, multiplier_mixin_lhs>&,
                            const engine<xtype1,itype1,
                                     output_mixin1,output_previous1,
                                     stream_mixin_rhs, multiplier_mixin_rhs>&);

    template <typename CharT, typename Traits,
              typename xtype1, typename itype1,
              typename output_mixin1, bool output_previous1,
              typename stream_mixin1, typename multiplier_mixin1>
    friend std::basic_ostream<CharT,Traits>&
    operator<<(std::basic_ostream<CharT,Traits>& out,
               const engine<xtype1,itype1,
                              output_mixin1,output_previous1,
                              stream_mixin1, multiplier_mixin1>&);

    template <typename CharT, typename Traits,
              typename xtype1, typename itype1,
              typename output_mixin1, bool output_previous1,
              typename stream_mixin1, typename multiplier_mixin1>
    friend std::basic_istream<CharT,Traits>&
    operator>>(std::basic_istream<CharT,Traits>& in,
               engine<xtype1, itype1,
                        output_mixin1, output_previous1,
                        stream_mixin1, multiplier_mixin1>& rng);
};

template <typename CharT, typename Traits,
          typename xtype, typename itype,
          typename output_mixin, bool output_previous,
          typename stream_mixin, typename multiplier_mixin>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>& out,
           const engine<xtype,itype,
                          output_mixin,output_previous,
                          stream_mixin, multiplier_mixin>& rng)
{
    using pcg_extras::operator<<;

    auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left);
    auto space = out.widen(' ');
    auto orig_fill = out.fill();

    out << rng.multiplier() << space
        << rng.increment() << space
        << rng.state_;

    out.flags(orig_flags);
    out.fill(orig_fill);
    return out;
}


template <typename CharT, typename Traits,
          typename xtype, typename itype,
          typename output_mixin, bool output_previous,
          typename stream_mixin, typename multiplier_mixin>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in,
           engine<xtype,itype,
                    output_mixin,output_previous,
                    stream_mixin, multiplier_mixin>& rng)
{
    using pcg_extras::operator>>;

    auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws);

    itype multiplier, increment, state;
    in >> multiplier >> increment >> state;

    if (!in.fail()) {
        bool good = true;
        if (multiplier != rng.multiplier()) {
           good = false;
        } else if (rng.can_specify_stream) {
           rng.set_stream(increment >> 1);
        } else if (increment != rng.increment()) {
           good = false;
        }
        if (good) {
            rng.state_ = state;
        } else {
            in.clear(std::ios::failbit);
        }
    }

    in.flags(orig_flags);
    return in;
}


template <typename xtype, typename itype,
          typename output_mixin, bool output_previous,
          typename stream_mixin, typename multiplier_mixin>
itype engine<xtype,itype,output_mixin,output_previous,stream_mixin,
             multiplier_mixin>::advance(
    itype state, itype delta, itype cur_mult, itype cur_plus)
{
    // The method used here is based on Brown, "Random Number Generation
    // with Arbitrary Stride,", Transactions of the American Nuclear
    // Society (Nov. 1994).  The algorithm is very similar to fast
    // exponentiation.
    //
    // Even though delta is an unsigned integer, we can pass a
    // signed integer to go backwards, it just goes "the long way round".

    constexpr itype ZERO = 0u;  // itype may be a non-trivial types, so
    constexpr itype ONE  = 1u;  // we define some ugly constants.
    itype acc_mult = 1;
    itype acc_plus = 0;
    while (delta > ZERO) {
       if (delta & ONE) {
          acc_mult *= cur_mult;
          acc_plus = acc_plus*cur_mult + cur_plus;
       }
       cur_plus = (cur_mult+ONE)*cur_plus;
       cur_mult *= cur_mult;
       delta >>= 1;
    }
    return acc_mult * state + acc_plus;
}

template <typename xtype, typename itype,
          typename output_mixin, bool output_previous,
          typename stream_mixin, typename multiplier_mixin>
itype engine<xtype,itype,output_mixin,output_previous,stream_mixin,
               multiplier_mixin>::distance(
    itype cur_state, itype newstate, itype cur_mult, itype cur_plus, itype mask)
{
    constexpr itype ONE  = 1u;  // itype could be weird, so use constant
    bool is_mcg = cur_plus == itype(0);
    itype the_bit = is_mcg ? itype(4u) : itype(1u);
    itype distance = 0u;
    while ((cur_state & mask) != (newstate & mask)) {
       if ((cur_state & the_bit) != (newstate & the_bit)) {
           cur_state = cur_state * cur_mult + cur_plus;
           distance |= the_bit;
       }
       assert((cur_state & the_bit) == (newstate & the_bit));
       the_bit <<= 1;
       cur_plus = (cur_mult+ONE)*cur_plus;
       cur_mult *= cur_mult;
    }
    return is_mcg ? distance >> 2 : distance;
}

template <typename xtype, typename itype,
          typename output_mixin, bool output_previous,
          typename stream_mixin_lhs, typename multiplier_mixin_lhs,
          typename stream_mixin_rhs, typename multiplier_mixin_rhs>
itype operator-(const engine<xtype,itype,
                               output_mixin,output_previous,
                               stream_mixin_lhs, multiplier_mixin_lhs>& lhs,
               const engine<xtype,itype,
                               output_mixin,output_previous,
                               stream_mixin_rhs, multiplier_mixin_rhs>& rhs)
{
    static_assert(
        std::is_same<stream_mixin_lhs, stream_mixin_rhs>::value &&
            std::is_same<multiplier_mixin_lhs, multiplier_mixin_rhs>::value,
        "Incomparable generators");
    if (lhs.increment() == rhs.increment()) {
       return rhs.distance(lhs.state_);
    } else  {
       constexpr itype ONE = 1u;
       itype lhs_diff = lhs.increment() + (lhs.multiplier()-ONE) * lhs.state_;
       itype rhs_diff = rhs.increment() + (rhs.multiplier()-ONE) * rhs.state_;
       if ((lhs_diff & itype(3u)) != (rhs_diff & itype(3u))) {
           rhs_diff = -rhs_diff;
       }
       return rhs.distance(rhs_diff, lhs_diff, rhs.multiplier(), itype(0u));
    }
}


template <typename xtype, typename itype,
          typename output_mixin, bool output_previous,
          typename stream_mixin_lhs, typename multiplier_mixin_lhs,
          typename stream_mixin_rhs, typename multiplier_mixin_rhs>
bool operator==(const engine<xtype,itype,
                               output_mixin,output_previous,
                               stream_mixin_lhs, multiplier_mixin_lhs>& lhs,
                const engine<xtype,itype,
                               output_mixin,output_previous,
                               stream_mixin_rhs, multiplier_mixin_rhs>& rhs)
{
    return    (lhs.multiplier() == rhs.multiplier())
           && (lhs.increment()  == rhs.increment())
           && (lhs.state_       == rhs.state_);
}

template <typename xtype, typename itype,
          typename output_mixin, bool output_previous,
          typename stream_mixin_lhs, typename multiplier_mixin_lhs,
          typename stream_mixin_rhs, typename multiplier_mixin_rhs>
inline bool operator!=(const engine<xtype,itype,
                               output_mixin,output_previous,
                               stream_mixin_lhs, multiplier_mixin_lhs>& lhs,
                       const engine<xtype,itype,
                               output_mixin,output_previous,
                               stream_mixin_rhs, multiplier_mixin_rhs>& rhs)
{
    return !operator==(lhs,rhs);
}


template <typename xtype, typename itype,
         template<typename XT,typename IT> class output_mixin,
         bool output_previous = (sizeof(itype) <= 8),
         template<typename IT> class multiplier_mixin = default_multiplier>
using oneseq_base  = engine<xtype, itype,
                        output_mixin<xtype, itype>, output_previous,
                        oneseq_stream<itype>,
                        multiplier_mixin<itype> >;

template <typename xtype, typename itype,
         template<typename XT,typename IT> class output_mixin,
         bool output_previous = (sizeof(itype) <= 8),
         template<typename IT> class multiplier_mixin = default_multiplier>
using unique_base = engine<xtype, itype,
                         output_mixin<xtype, itype>, output_previous,
                         unique_stream<itype>,
                         multiplier_mixin<itype> >;

template <typename xtype, typename itype,
         template<typename XT,typename IT> class output_mixin,
         bool output_previous = (sizeof(itype) <= 8),
         template<typename IT> class multiplier_mixin = default_multiplier>
using setseq_base = engine<xtype, itype,
                         output_mixin<xtype, itype>, output_previous,
                         specific_stream<itype>,
                         multiplier_mixin<itype> >;

template <typename xtype, typename itype,
         template<typename XT,typename IT> class output_mixin,
         bool output_previous = (sizeof(itype) <= 8),
         template<typename IT> class multiplier_mixin = default_multiplier>
using mcg_base = engine<xtype, itype,
                      output_mixin<xtype, itype>, output_previous,
                      no_stream<itype>,
                      multiplier_mixin<itype> >;

/*
 * OUTPUT FUNCTIONS.
 *
 * These are the core of the PCG generation scheme.  They specify how to
 * turn the base LCG's internal state into the output value of the final
 * generator.
 *
 * They're implemented as mixin classes.
 *
 * All of the classes have code that is written to allow it to be applied
 * at *arbitrary* bit sizes, although in practice they'll only be used at
 * standard sizes supported by C++.
 */

/*
 * XSH RS -- high xorshift, followed by a random shift
 *
 * Fast.  A good performer.
 */

template <typename xtype, typename itype>
struct xsh_rs_mixin {
    static xtype output(itype internal)
    {
        constexpr bitcount_t bits        = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t xtypebits   = bitcount_t(sizeof(xtype) * 8);
        constexpr bitcount_t sparebits   = bits - xtypebits;
        constexpr bitcount_t opbits =
                              sparebits-5 >= 64 ? 5
                            : sparebits-4 >= 32 ? 4
                            : sparebits-3 >= 16 ? 3
                            : sparebits-2 >= 4  ? 2
                            : sparebits-1 >= 1  ? 1
                            :                     0;
        constexpr bitcount_t mask = (1 << opbits) - 1;
        constexpr bitcount_t maxrandshift  = mask;
        constexpr bitcount_t topspare     = opbits;
        constexpr bitcount_t bottomspare = sparebits - topspare;
        constexpr bitcount_t xshift     = topspare + (xtypebits+maxrandshift)/2;
        bitcount_t rshift =
            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;
        internal ^= internal >> xshift;
        xtype result = xtype(internal >> (bottomspare - maxrandshift + rshift));
        return result;
    }
};

/*
 * XSH RR -- high xorshift, followed by a random rotate
 *
 * Fast.  A good performer.  Slightly better statistically than XSH RS.
 */

template <typename xtype, typename itype>
struct xsh_rr_mixin {
    static xtype output(itype internal)
    {
        constexpr bitcount_t bits        = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t xtypebits   = bitcount_t(sizeof(xtype)*8);
        constexpr bitcount_t sparebits   = bits - xtypebits;
        constexpr bitcount_t wantedopbits =
                              xtypebits >= 128 ? 7
                            : xtypebits >=  64 ? 6
                            : xtypebits >=  32 ? 5
                            : xtypebits >=  16 ? 4
                            :                    3;
        constexpr bitcount_t opbits =
                              sparebits >= wantedopbits ? wantedopbits
                                                        : sparebits;
        constexpr bitcount_t amplifier = wantedopbits - opbits;
        constexpr bitcount_t mask = (1 << opbits) - 1;
        constexpr bitcount_t topspare    = opbits;
        constexpr bitcount_t bottomspare = sparebits - topspare;
        constexpr bitcount_t xshift      = (topspare + xtypebits)/2;
        bitcount_t rot = opbits ? bitcount_t(internal >> (bits - opbits)) & mask
                                : 0;
        bitcount_t amprot = (rot << amplifier) & mask;
        internal ^= internal >> xshift;
        xtype result = xtype(internal >> bottomspare);
        result = rotr(result, amprot);
        return result;
    }
};

/*
 * RXS -- random xorshift
 */

template <typename xtype, typename itype>
struct rxs_mixin {
static xtype output_rxs(itype internal)
    {
        constexpr bitcount_t bits        = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t xtypebits   = bitcount_t(sizeof(xtype)*8);
        constexpr bitcount_t shift       = bits - xtypebits;
        constexpr bitcount_t extrashift  = (xtypebits - shift)/2;
        bitcount_t rshift = shift > 64+8 ? (internal >> (bits - 6)) & 63
                       : shift > 32+4 ? (internal >> (bits - 5)) & 31
                       : shift > 16+2 ? (internal >> (bits - 4)) & 15
                       : shift >  8+1 ? (internal >> (bits - 3)) & 7
                       : shift >  4+1 ? (internal >> (bits - 2)) & 3
                       : shift >  2+1 ? (internal >> (bits - 1)) & 1
                       :              0;
        internal ^= internal >> (shift + extrashift - rshift);
        xtype result = internal >> rshift;
        return result;
    }
};

/*
 * RXS M XS -- random xorshift, mcg multiply, fixed xorshift
 *
 * The most statistically powerful generator, but all those steps
 * make it slower than some of the others.  We give it the rottenest jobs.
 *
 * Because it's usually used in contexts where the state type and the
 * result type are the same, it is a permutation and is thus invertable.
 * We thus provide a function to invert it.  This function is used to
 * for the "inside out" generator used by the extended generator.
 */

/* Defined type-based concepts for the multiplication step.  They're actually
 * all derived by truncating the 128-bit, which was computed to be a good
 * "universal" constant.
 */

template <typename T>
struct mcg_multiplier {
    // Not defined for an arbitrary type
};

template <typename T>
struct mcg_unmultiplier {
    // Not defined for an arbitrary type
};

PCG_DEFINE_CONSTANT(uint8_t,  mcg, multiplier,   217U)
PCG_DEFINE_CONSTANT(uint8_t,  mcg, unmultiplier, 105U)

PCG_DEFINE_CONSTANT(uint16_t, mcg, multiplier,   62169U)
PCG_DEFINE_CONSTANT(uint16_t, mcg, unmultiplier, 28009U)

PCG_DEFINE_CONSTANT(uint32_t, mcg, multiplier,   277803737U)
PCG_DEFINE_CONSTANT(uint32_t, mcg, unmultiplier, 2897767785U)

PCG_DEFINE_CONSTANT(uint64_t, mcg, multiplier,   12605985483714917081ULL)
PCG_DEFINE_CONSTANT(uint64_t, mcg, unmultiplier, 15009553638781119849ULL)

PCG_DEFINE_CONSTANT(pcg128_t, mcg, multiplier,
        PCG_128BIT_CONSTANT(17766728186571221404ULL, 12605985483714917081ULL))
PCG_DEFINE_CONSTANT(pcg128_t, mcg, unmultiplier,
        PCG_128BIT_CONSTANT(14422606686972528997ULL, 15009553638781119849ULL))


template <typename xtype, typename itype>
struct rxs_m_xs_mixin {
    static xtype output(itype internal)
    {
        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);
        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t opbits = xtypebits >= 128 ? 6
                                 : xtypebits >=  64 ? 5
                                 : xtypebits >=  32 ? 4
                                 : xtypebits >=  16 ? 3
                                 :                    2;
        constexpr bitcount_t shift = bits - xtypebits;
        constexpr bitcount_t mask = (1 << opbits) - 1;
        bitcount_t rshift =
            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;
        internal ^= internal >> (opbits + rshift);
        internal *= mcg_multiplier<itype>::multiplier();
        xtype result = internal >> shift;
        result ^= result >> ((2U*xtypebits+2U)/3U);
        return result;
    }

    static itype unoutput(itype internal)
    {
        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t opbits = bits >= 128 ? 6
                                 : bits >=  64 ? 5
                                 : bits >=  32 ? 4
                                 : bits >=  16 ? 3
                                 :               2;
        constexpr bitcount_t mask = (1 << opbits) - 1;

        internal = unxorshift(internal, bits, (2U*bits+2U)/3U);

        internal *= mcg_unmultiplier<itype>::unmultiplier();

        bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0;
        internal = unxorshift(internal, bits, opbits + rshift);

        return internal;
    }
};


/*
 * RXS M -- random xorshift, mcg multiply
 */

template <typename xtype, typename itype>
struct rxs_m_mixin {
    static xtype output(itype internal)
    {
        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);
        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t opbits = xtypebits >= 128 ? 6
                                 : xtypebits >=  64 ? 5
                                 : xtypebits >=  32 ? 4
                                 : xtypebits >=  16 ? 3
                                 :                    2;
        constexpr bitcount_t shift = bits - xtypebits;
        constexpr bitcount_t mask = (1 << opbits) - 1;
        bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0;
        internal ^= internal >> (opbits + rshift);
        internal *= mcg_multiplier<itype>::multiplier();
        xtype result = internal >> shift;
        return result;
    }
};


/*
 * DXSM -- double xorshift multiply
 *
 * This is a new, more powerful output permutation (added in 2019).  It's
 * a more comprehensive scrambling than RXS M, but runs faster on 128-bit
 * types.  Although primarily intended for use at large sizes, also works
 * at smaller sizes as well.
 *
 * This permutation is similar to xorshift multiply hash functions, except
 * that one of the multipliers is the LCG multiplier (to avoid needing to
 * have a second constant) and the other is based on the low-order bits.
 * This latter aspect means that the scrambling applied to the high bits
 * depends on the low bits, and makes it (to my eye) impractical to back
 * out the permutation without having the low-order bits.
 */

template <typename xtype, typename itype>
struct dxsm_mixin {
    inline xtype output(itype internal)
    {
        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);
        constexpr bitcount_t itypebits = bitcount_t(sizeof(itype) * 8);
        static_assert(xtypebits <= itypebits/2,
                      "Output type must be half the size of the state type.");

        xtype hi = xtype(internal >> (itypebits - xtypebits));
        xtype lo = xtype(internal);

        lo |= 1;
        hi ^= hi >> (xtypebits/2);
	hi *= xtype(cheap_multiplier<itype>::multiplier());
	hi ^= hi >> (3*(xtypebits/4));
	hi *= lo;
	return hi;
    }
};


/*
 * XSL RR -- fixed xorshift (to low bits), random rotate
 *
 * Useful for 128-bit types that are split across two CPU registers.
 */

template <typename xtype, typename itype>
struct xsl_rr_mixin {
    static xtype output(itype internal)
    {
        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);
        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t sparebits = bits - xtypebits;
        constexpr bitcount_t wantedopbits = xtypebits >= 128 ? 7
                                       : xtypebits >=  64 ? 6
                                       : xtypebits >=  32 ? 5
                                       : xtypebits >=  16 ? 4
                                       :                    3;
        constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits
                                                             : sparebits;
        constexpr bitcount_t amplifier = wantedopbits - opbits;
        constexpr bitcount_t mask = (1 << opbits) - 1;
        constexpr bitcount_t topspare = sparebits;
        constexpr bitcount_t bottomspare = sparebits - topspare;
        constexpr bitcount_t xshift = (topspare + xtypebits) / 2;

        bitcount_t rot =
            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;
        bitcount_t amprot = (rot << amplifier) & mask;
        internal ^= internal >> xshift;
        xtype result = xtype(internal >> bottomspare);
        result = rotr(result, amprot);
        return result;
    }
};


/*
 * XSL RR RR -- fixed xorshift (to low bits), random rotate (both parts)
 *
 * Useful for 128-bit types that are split across two CPU registers.
 * If you really want an invertable 128-bit RNG, I guess this is the one.
 */

template <typename T> struct halfsize_trait {};
template <> struct halfsize_trait<pcg128_t>  { typedef uint64_t type; };
template <> struct halfsize_trait<uint64_t>  { typedef uint32_t type; };
template <> struct halfsize_trait<uint32_t>  { typedef uint16_t type; };
template <> struct halfsize_trait<uint16_t>  { typedef uint8_t type;  };

template <typename xtype, typename itype>
struct xsl_rr_rr_mixin {
    typedef typename halfsize_trait<itype>::type htype;

    static itype output(itype internal)
    {
        constexpr bitcount_t htypebits = bitcount_t(sizeof(htype) * 8);
        constexpr bitcount_t bits      = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t sparebits = bits - htypebits;
        constexpr bitcount_t wantedopbits = htypebits >= 128 ? 7
                                       : htypebits >=  64 ? 6
                                       : htypebits >=  32 ? 5
                                       : htypebits >=  16 ? 4
                                       :                    3;
        constexpr bitcount_t opbits = sparebits >= wantedopbits ? wantedopbits
                                                                : sparebits;
        constexpr bitcount_t amplifier = wantedopbits - opbits;
        constexpr bitcount_t mask = (1 << opbits) - 1;
        constexpr bitcount_t topspare = sparebits;
        constexpr bitcount_t xshift = (topspare + htypebits) / 2;

        bitcount_t rot =
            opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;
        bitcount_t amprot = (rot << amplifier) & mask;
        internal ^= internal >> xshift;
        htype lowbits = htype(internal);
        lowbits = rotr(lowbits, amprot);
        htype highbits = htype(internal >> topspare);
        bitcount_t rot2 = lowbits & mask;
        bitcount_t amprot2 = (rot2 << amplifier) & mask;
        highbits = rotr(highbits, amprot2);
        return (itype(highbits) << topspare) ^ itype(lowbits);
    }
};


/*
 * XSH -- fixed xorshift (to high bits)
 *
 * You shouldn't use this at 64-bits or less.
 */

template <typename xtype, typename itype>
struct xsh_mixin {
    static xtype output(itype internal)
    {
        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);
        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t sparebits = bits - xtypebits;
        constexpr bitcount_t topspare = 0;
        constexpr bitcount_t bottomspare = sparebits - topspare;
        constexpr bitcount_t xshift = (topspare + xtypebits) / 2;

        internal ^= internal >> xshift;
        xtype result = internal >> bottomspare;
        return result;
    }
};

/*
 * XSL -- fixed xorshift (to low bits)
 *
 * You shouldn't use this at 64-bits or less.
 */

template <typename xtype, typename itype>
struct xsl_mixin {
    inline xtype output(itype internal)
    {
        constexpr bitcount_t xtypebits = bitcount_t(sizeof(xtype) * 8);
        constexpr bitcount_t bits = bitcount_t(sizeof(itype) * 8);
        constexpr bitcount_t sparebits = bits - xtypebits;
        constexpr bitcount_t topspare = sparebits;
        constexpr bitcount_t bottomspare = sparebits - topspare;
        constexpr bitcount_t xshift = (topspare + xtypebits) / 2;

        internal ^= internal >> xshift;
        xtype result = internal >> bottomspare;
        return result;
    }
};


/* ---- End of Output Functions ---- */


template <typename baseclass>
struct inside_out : private baseclass {
    inside_out() = delete;

    typedef typename baseclass::result_type result_type;
    typedef typename baseclass::state_type  state_type;
    static_assert(sizeof(result_type) == sizeof(state_type),
                  "Require a RNG whose output function is a permutation");

    static bool external_step(result_type& randval, size_t i)
    {
        state_type state = baseclass::unoutput(randval);
        state = state * baseclass::multiplier() + baseclass::increment()
                + state_type(i*2);
        result_type result = baseclass::output(state);
        randval = result;
        state_type zero =
            baseclass::is_mcg ? state & state_type(3U) : state_type(0U);
        return result == zero;
    }

    static bool external_advance(result_type& randval, size_t i,
                                 result_type delta, bool forwards = true)
    {
        state_type state = baseclass::unoutput(randval);
        state_type mult  = baseclass::multiplier();
        state_type inc   = baseclass::increment() + state_type(i*2);
        state_type zero =
            baseclass::is_mcg ? state & state_type(3U) : state_type(0U);
        state_type dist_to_zero = baseclass::distance(state, zero, mult, inc);
        bool crosses_zero =
            forwards ? dist_to_zero <= delta
                     : (-dist_to_zero) <= delta;
        if (!forwards)
            delta = -delta;
        state = baseclass::advance(state, delta, mult, inc);
        randval = baseclass::output(state);
        return crosses_zero;
    }
};


template <bitcount_t table_pow2, bitcount_t advance_pow2, typename baseclass, typename extvalclass, bool kdd = true>
class pcg_extended : public baseclass {
public:
    typedef typename baseclass::state_type  state_type;
    typedef typename baseclass::result_type result_type;
    typedef inside_out<extvalclass> insideout;

private:
    static constexpr bitcount_t rtypebits = sizeof(result_type)*8;
    static constexpr bitcount_t stypebits = sizeof(state_type)*8;

    static constexpr bitcount_t tick_limit_pow2 = 64U;

    static constexpr size_t table_size  = 1UL << table_pow2;
    static constexpr size_t table_shift = stypebits - table_pow2;
    static constexpr state_type table_mask =
        (state_type(1U) << table_pow2) - state_type(1U);

    static constexpr bool   may_tick  =
        (advance_pow2 < stypebits) && (advance_pow2 < tick_limit_pow2);
    static constexpr size_t tick_shift = stypebits - advance_pow2;
    static constexpr state_type tick_mask  =
        may_tick ? state_type(
                       (uint64_t(1) << (advance_pow2*may_tick)) - 1)
                                        // ^-- stupidity to appease GCC warnings
                 : ~state_type(0U);

    static constexpr bool may_tock = stypebits < tick_limit_pow2;

    result_type data_[table_size];

    PCG_NOINLINE void advance_table();

    PCG_NOINLINE void advance_table(state_type delta, bool isForwards = true);

    result_type& get_extended_value()
    {
        state_type state = this->state_;
        if (kdd && baseclass::is_mcg) {
            // The low order bits of an MCG are constant, so drop them.
            state >>= 2;
        }
        size_t index       = kdd ? state &  table_mask
                                 : state >> table_shift;

        if (may_tick) {
            bool tick = kdd ? (state & tick_mask) == state_type(0u)
                            : (state >> tick_shift) == state_type(0u);
            if (tick)
                    advance_table();
        }
        if (may_tock) {
            bool tock = state == state_type(0u);
            if (tock)
                advance_table();
        }
        return data_[index];
    }

public:
    static constexpr size_t period_pow2()
    {
        return baseclass::period_pow2() + table_size*extvalclass::period_pow2();
    }

    PCG_ALWAYS_INLINE result_type operator()()
    {
        result_type rhs = get_extended_value();
        result_type lhs = this->baseclass::operator()();
        return lhs ^ rhs;
    }

    result_type operator()(result_type upper_bound)
    {
        return bounded_rand(*this, upper_bound);
    }

    void set(result_type wanted)
    {
        result_type& rhs = get_extended_value();
        result_type lhs = this->baseclass::operator()();
        rhs = lhs ^ wanted;
    }

    void advance(state_type distance, bool forwards = true);

    void backstep(state_type distance)
    {
        advance(distance, false);
    }

    pcg_extended(const result_type* data)
        : baseclass()
    {
        datainit(data);
    }

    pcg_extended(const result_type* data, state_type seed)
        : baseclass(seed)
    {
        datainit(data);
    }

    // This function may or may not exist.  It thus has to be a template
    // to use SFINAE; users don't have to worry about its template-ness.

    template <typename bc = baseclass>
    pcg_extended(const result_type* data, state_type seed,
            typename bc::stream_state stream_seed)
        : baseclass(seed, stream_seed)
    {
        datainit(data);
    }

    pcg_extended()
        : baseclass()
    {
        selfinit();
    }

    pcg_extended(state_type seed)
        : baseclass(seed)
    {
        selfinit();
    }

    // This function may or may not exist.  It thus has to be a template
    // to use SFINAE; users don't have to worry about its template-ness.

    template <typename bc = baseclass>
    pcg_extended(state_type seed, typename bc::stream_state stream_seed)
        : baseclass(seed, stream_seed)
    {
        selfinit();
    }

private:
    void selfinit();
    void datainit(const result_type* data);

public:

    template<typename SeedSeq, typename = typename std::enable_if<
           !std::is_convertible<SeedSeq, result_type>::value
        && !std::is_convertible<SeedSeq, pcg_extended>::value>::type>
    pcg_extended(SeedSeq&& seedSeq)
        : baseclass(seedSeq)
    {
        generate_to<table_size>(seedSeq, data_);
    }

    template<typename... Args>
    void seed(Args&&... args)
    {
        new (this) pcg_extended(std::forward<Args>(args)...);
    }

    template <bitcount_t table_pow2_, bitcount_t advance_pow2_,
              typename baseclass_, typename extvalclass_, bool kdd_>
    friend bool operator==(const pcg_extended<table_pow2_, advance_pow2_,
                                              baseclass_, extvalclass_, kdd_>&,
                           const pcg_extended<table_pow2_, advance_pow2_,
                                              baseclass_, extvalclass_, kdd_>&);

    template <typename CharT, typename Traits,
              bitcount_t table_pow2_, bitcount_t advance_pow2_,
              typename baseclass_, typename extvalclass_, bool kdd_>
    friend std::basic_ostream<CharT,Traits>&
    operator<<(std::basic_ostream<CharT,Traits>& out,
               const pcg_extended<table_pow2_, advance_pow2_,
                              baseclass_, extvalclass_, kdd_>&);

    template <typename CharT, typename Traits,
              bitcount_t table_pow2_, bitcount_t advance_pow2_,
              typename baseclass_, typename extvalclass_, bool kdd_>
    friend std::basic_istream<CharT,Traits>&
    operator>>(std::basic_istream<CharT,Traits>& in,
               pcg_extended<table_pow2_, advance_pow2_,
                        baseclass_, extvalclass_, kdd_>&);

};


template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
void pcg_extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::datainit(
         const result_type* data)
{
    for (size_t i = 0; i < table_size; ++i)
        data_[i] = data[i];
}

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
void pcg_extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::selfinit()
{
    // We need to fill the extended table with something, and we have
    // very little provided data, so we use the base generator to
    // produce values.  Although not ideal (use a seed sequence, folks!),
    // unexpected correlations are mitigated by
    //      - using XOR differences rather than the number directly
    //      - the way the table is accessed, its values *won't* be accessed
    //        in the same order the were written.
    //      - any strange correlations would only be apparent if we
    //        were to backstep the generator so that the base generator
    //        was generating the same values again
    result_type lhs = baseclass::operator()();
    result_type rhs = baseclass::operator()();
    result_type xdiff = lhs - rhs;
    for (size_t i = 0; i < table_size; ++i) {
        data_[i] = baseclass::operator()() ^ xdiff;
    }
}

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
bool operator==(const pcg_extended<table_pow2, advance_pow2,
                               baseclass, extvalclass, kdd>& lhs,
                const pcg_extended<table_pow2, advance_pow2,
                               baseclass, extvalclass, kdd>& rhs)
{
    auto& base_lhs = static_cast<const baseclass&>(lhs);
    auto& base_rhs = static_cast<const baseclass&>(rhs);
    return base_lhs == base_rhs
        && std::equal(
               std::begin(lhs.data_), std::end(lhs.data_),
               std::begin(rhs.data_)
           );
}

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
inline bool operator!=(const pcg_extended<table_pow2, advance_pow2,
                                      baseclass, extvalclass, kdd>& lhs,
                       const pcg_extended<table_pow2, advance_pow2,
                                      baseclass, extvalclass, kdd>& rhs)
{
    return !operator==(lhs, rhs);
}

template <typename CharT, typename Traits,
          bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>& out,
           const pcg_extended<table_pow2, advance_pow2,
                          baseclass, extvalclass, kdd>& rng)
{
    auto orig_flags = out.flags(std::ios_base::dec | std::ios_base::left);
    auto space = out.widen(' ');
    auto orig_fill = out.fill();

    out << rng.multiplier() << space
        << rng.increment() << space
        << rng.state_;

    for (const auto& datum : rng.data_)
        out << space << datum;

    out.flags(orig_flags);
    out.fill(orig_fill);
    return out;
}

template <typename CharT, typename Traits,
          bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in,
           pcg_extended<table_pow2, advance_pow2,
                    baseclass, extvalclass, kdd>& rng)
{
    pcg_extended<table_pow2, advance_pow2, baseclass, extvalclass> new_rng;
    auto& base_rng = static_cast<baseclass&>(new_rng);
    in >> base_rng;

    if (in.fail())
        return in;

    auto orig_flags = in.flags(std::ios_base::dec | std::ios_base::skipws);

    for (auto& datum : new_rng.data_) {
        in >> datum;
        if (in.fail())
            goto bail;
    }

    rng = new_rng;

bail:
    in.flags(orig_flags);
    return in;
}



template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
void
pcg_extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance_table()
{
    bool carry = false;
    for (size_t i = 0; i < table_size; ++i) {
        if (carry) {
            carry = insideout::external_step(data_[i],i+1);
        }
        bool carry2 = insideout::external_step(data_[i],i+1);
        carry = carry || carry2;
    }
}

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
void
pcg_extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance_table(
        state_type delta, bool isForwards)
{
    typedef typename baseclass::state_type   base_state_t;
    typedef typename extvalclass::state_type ext_state_t;
    constexpr bitcount_t basebits = sizeof(base_state_t)*8;
    constexpr bitcount_t extbits  = sizeof(ext_state_t)*8;
    static_assert(basebits <= extbits || advance_pow2 > 0,
                  "Current implementation might overflow its carry");

    base_state_t carry = 0;
    for (size_t i = 0; i < table_size; ++i) {
        base_state_t total_delta = carry + delta;
        ext_state_t  trunc_delta = ext_state_t(total_delta);
        if (basebits > extbits) {
            carry = total_delta >> extbits;
        } else {
            carry = 0;
        }
        carry +=
            insideout::external_advance(data_[i],i+1, trunc_delta, isForwards);
    }
}

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename baseclass, typename extvalclass, bool kdd>
void pcg_extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::advance(
    state_type distance, bool forwards)
{
    static_assert(kdd,
        "Efficient advance is too hard for non-kdd extension. "
        "For a weak advance, cast to base class");
    state_type zero =
        baseclass::is_mcg ? this->state_ & state_type(3U) : state_type(0U);
    if (may_tick) {
        state_type ticks = distance >> (advance_pow2*may_tick);
                                        // ^-- stupidity to appease GCC
                                        // warnings
        state_type adv_mask =
            baseclass::is_mcg ? tick_mask << 2 : tick_mask;
        state_type next_advance_distance = this->distance(zero, adv_mask);
        if (!forwards)
            next_advance_distance = (-next_advance_distance) & tick_mask;
        if (next_advance_distance < (distance & tick_mask)) {
            ++ticks;
        }
        if (ticks)
            advance_table(ticks, forwards);
    }
    if (forwards) {
        if (may_tock && this->distance(zero) <= distance)
            advance_table();
        baseclass::advance(distance);
    } else {
        if (may_tock && -(this->distance(zero)) <= distance)
            advance_table(state_type(1U), false);
        baseclass::advance(-distance);
    }
}

} // namespace pcg_detail

namespace pcg_engines {

using namespace pcg_detail;

/* Predefined types for XSH RS */

typedef oneseq_base<uint8_t,  uint16_t, xsh_rs_mixin>  oneseq_xsh_rs_16_8;
typedef oneseq_base<uint16_t, uint32_t, xsh_rs_mixin>  oneseq_xsh_rs_32_16;
typedef oneseq_base<uint32_t, uint64_t, xsh_rs_mixin>  oneseq_xsh_rs_64_32;
typedef oneseq_base<uint64_t, pcg128_t, xsh_rs_mixin>  oneseq_xsh_rs_128_64;
typedef oneseq_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>
                                                       cm_oneseq_xsh_rs_128_64;

typedef unique_base<uint8_t,  uint16_t, xsh_rs_mixin>  unique_xsh_rs_16_8;
typedef unique_base<uint16_t, uint32_t, xsh_rs_mixin>  unique_xsh_rs_32_16;
typedef unique_base<uint32_t, uint64_t, xsh_rs_mixin>  unique_xsh_rs_64_32;
typedef unique_base<uint64_t, pcg128_t, xsh_rs_mixin>  unique_xsh_rs_128_64;
typedef unique_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>
                                                       cm_unique_xsh_rs_128_64;

typedef setseq_base<uint8_t,  uint16_t, xsh_rs_mixin>  setseq_xsh_rs_16_8;
typedef setseq_base<uint16_t, uint32_t, xsh_rs_mixin>  setseq_xsh_rs_32_16;
typedef setseq_base<uint32_t, uint64_t, xsh_rs_mixin>  setseq_xsh_rs_64_32;
typedef setseq_base<uint64_t, pcg128_t, xsh_rs_mixin>  setseq_xsh_rs_128_64;
typedef setseq_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>
                                                       cm_setseq_xsh_rs_128_64;

typedef mcg_base<uint8_t,  uint16_t, xsh_rs_mixin>  mcg_xsh_rs_16_8;
typedef mcg_base<uint16_t, uint32_t, xsh_rs_mixin>  mcg_xsh_rs_32_16;
typedef mcg_base<uint32_t, uint64_t, xsh_rs_mixin>  mcg_xsh_rs_64_32;
typedef mcg_base<uint64_t, pcg128_t, xsh_rs_mixin>  mcg_xsh_rs_128_64;
typedef mcg_base<uint64_t, pcg128_t, xsh_rs_mixin, true, cheap_multiplier>
                                                    cm_mcg_xsh_rs_128_64;

/* Predefined types for XSH RR */

typedef oneseq_base<uint8_t,  uint16_t, xsh_rr_mixin>  oneseq_xsh_rr_16_8;
typedef oneseq_base<uint16_t, uint32_t, xsh_rr_mixin>  oneseq_xsh_rr_32_16;
typedef oneseq_base<uint32_t, uint64_t, xsh_rr_mixin>  oneseq_xsh_rr_64_32;
typedef oneseq_base<uint64_t, pcg128_t, xsh_rr_mixin>  oneseq_xsh_rr_128_64;
typedef oneseq_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>
                                                       cm_oneseq_xsh_rr_128_64;

typedef unique_base<uint8_t,  uint16_t, xsh_rr_mixin>  unique_xsh_rr_16_8;
typedef unique_base<uint16_t, uint32_t, xsh_rr_mixin>  unique_xsh_rr_32_16;
typedef unique_base<uint32_t, uint64_t, xsh_rr_mixin>  unique_xsh_rr_64_32;
typedef unique_base<uint64_t, pcg128_t, xsh_rr_mixin>  unique_xsh_rr_128_64;
typedef unique_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>
                                                       cm_unique_xsh_rr_128_64;

typedef setseq_base<uint8_t,  uint16_t, xsh_rr_mixin>  setseq_xsh_rr_16_8;
typedef setseq_base<uint16_t, uint32_t, xsh_rr_mixin>  setseq_xsh_rr_32_16;
typedef setseq_base<uint32_t, uint64_t, xsh_rr_mixin>  setseq_xsh_rr_64_32;
typedef setseq_base<uint64_t, pcg128_t, xsh_rr_mixin>  setseq_xsh_rr_128_64;
typedef setseq_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>
                                                       cm_setseq_xsh_rr_128_64;

typedef mcg_base<uint8_t,  uint16_t, xsh_rr_mixin>  mcg_xsh_rr_16_8;
typedef mcg_base<uint16_t, uint32_t, xsh_rr_mixin>  mcg_xsh_rr_32_16;
typedef mcg_base<uint32_t, uint64_t, xsh_rr_mixin>  mcg_xsh_rr_64_32;
typedef mcg_base<uint64_t, pcg128_t, xsh_rr_mixin>  mcg_xsh_rr_128_64;
typedef mcg_base<uint64_t, pcg128_t, xsh_rr_mixin, true, cheap_multiplier>
                                                    cm_mcg_xsh_rr_128_64;


/* Predefined types for RXS M XS */

typedef oneseq_base<uint8_t,  uint8_t, rxs_m_xs_mixin>   oneseq_rxs_m_xs_8_8;
typedef oneseq_base<uint16_t, uint16_t, rxs_m_xs_mixin>  oneseq_rxs_m_xs_16_16;
typedef oneseq_base<uint32_t, uint32_t, rxs_m_xs_mixin>  oneseq_rxs_m_xs_32_32;
typedef oneseq_base<uint64_t, uint64_t, rxs_m_xs_mixin>  oneseq_rxs_m_xs_64_64;
typedef oneseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin>
                                                        oneseq_rxs_m_xs_128_128;
typedef oneseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin, true, cheap_multiplier>
                                                     cm_oneseq_rxs_m_xs_128_128;

typedef unique_base<uint8_t,  uint8_t, rxs_m_xs_mixin>  unique_rxs_m_xs_8_8;
typedef unique_base<uint16_t, uint16_t, rxs_m_xs_mixin> unique_rxs_m_xs_16_16;
typedef unique_base<uint32_t, uint32_t, rxs_m_xs_mixin> unique_rxs_m_xs_32_32;
typedef unique_base<uint64_t, uint64_t, rxs_m_xs_mixin> unique_rxs_m_xs_64_64;
typedef unique_base<pcg128_t, pcg128_t, rxs_m_xs_mixin> unique_rxs_m_xs_128_128;
typedef unique_base<pcg128_t, pcg128_t, rxs_m_xs_mixin, true, cheap_multiplier>
                                                     cm_unique_rxs_m_xs_128_128;

typedef setseq_base<uint8_t,  uint8_t, rxs_m_xs_mixin>  setseq_rxs_m_xs_8_8;
typedef setseq_base<uint16_t, uint16_t, rxs_m_xs_mixin> setseq_rxs_m_xs_16_16;
typedef setseq_base<uint32_t, uint32_t, rxs_m_xs_mixin> setseq_rxs_m_xs_32_32;
typedef setseq_base<uint64_t, uint64_t, rxs_m_xs_mixin> setseq_rxs_m_xs_64_64;
typedef setseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin> setseq_rxs_m_xs_128_128;
typedef setseq_base<pcg128_t, pcg128_t, rxs_m_xs_mixin, true, cheap_multiplier>
                                                     cm_setseq_rxs_m_xs_128_128;

                // MCG versions don't make sense here, so aren't defined.

/* Predefined types for RXS M */

typedef oneseq_base<uint8_t,  uint16_t, rxs_m_mixin>  oneseq_rxs_m_16_8;
typedef oneseq_base<uint16_t, uint32_t, rxs_m_mixin>  oneseq_rxs_m_32_16;
typedef oneseq_base<uint32_t, uint64_t, rxs_m_mixin>  oneseq_rxs_m_64_32;
typedef oneseq_base<uint64_t, pcg128_t, rxs_m_mixin>  oneseq_rxs_m_128_64;
typedef oneseq_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>
                                                      cm_oneseq_rxs_m_128_64;

typedef unique_base<uint8_t,  uint16_t, rxs_m_mixin>  unique_rxs_m_16_8;
typedef unique_base<uint16_t, uint32_t, rxs_m_mixin>  unique_rxs_m_32_16;
typedef unique_base<uint32_t, uint64_t, rxs_m_mixin>  unique_rxs_m_64_32;
typedef unique_base<uint64_t, pcg128_t, rxs_m_mixin>  unique_rxs_m_128_64;
typedef unique_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>
                                                      cm_unique_rxs_m_128_64;

typedef setseq_base<uint8_t,  uint16_t, rxs_m_mixin>  setseq_rxs_m_16_8;
typedef setseq_base<uint16_t, uint32_t, rxs_m_mixin>  setseq_rxs_m_32_16;
typedef setseq_base<uint32_t, uint64_t, rxs_m_mixin>  setseq_rxs_m_64_32;
typedef setseq_base<uint64_t, pcg128_t, rxs_m_mixin>  setseq_rxs_m_128_64;
typedef setseq_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>
                                                      cm_setseq_rxs_m_128_64;

typedef mcg_base<uint8_t,  uint16_t, rxs_m_mixin>  mcg_rxs_m_16_8;
typedef mcg_base<uint16_t, uint32_t, rxs_m_mixin>  mcg_rxs_m_32_16;
typedef mcg_base<uint32_t, uint64_t, rxs_m_mixin>  mcg_rxs_m_64_32;
typedef mcg_base<uint64_t, pcg128_t, rxs_m_mixin>  mcg_rxs_m_128_64;
typedef mcg_base<uint64_t, pcg128_t, rxs_m_mixin, true, cheap_multiplier>
                                                   cm_mcg_rxs_m_128_64;

/* Predefined types for DXSM */

typedef oneseq_base<uint8_t,  uint16_t, dxsm_mixin>  oneseq_dxsm_16_8;
typedef oneseq_base<uint16_t, uint32_t, dxsm_mixin>  oneseq_dxsm_32_16;
typedef oneseq_base<uint32_t, uint64_t, dxsm_mixin>  oneseq_dxsm_64_32;
typedef oneseq_base<uint64_t, pcg128_t, dxsm_mixin>  oneseq_dxsm_128_64;
typedef oneseq_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>
                                                     cm_oneseq_dxsm_128_64;

typedef unique_base<uint8_t,  uint16_t, dxsm_mixin>  unique_dxsm_16_8;
typedef unique_base<uint16_t, uint32_t, dxsm_mixin>  unique_dxsm_32_16;
typedef unique_base<uint32_t, uint64_t, dxsm_mixin>  unique_dxsm_64_32;
typedef unique_base<uint64_t, pcg128_t, dxsm_mixin>  unique_dxsm_128_64;
typedef unique_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>
                                                     cm_unique_dxsm_128_64;

typedef setseq_base<uint8_t,  uint16_t, dxsm_mixin>  setseq_dxsm_16_8;
typedef setseq_base<uint16_t, uint32_t, dxsm_mixin>  setseq_dxsm_32_16;
typedef setseq_base<uint32_t, uint64_t, dxsm_mixin>  setseq_dxsm_64_32;
typedef setseq_base<uint64_t, pcg128_t, dxsm_mixin>  setseq_dxsm_128_64;
typedef setseq_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>
                                                     cm_setseq_dxsm_128_64;

typedef mcg_base<uint8_t,  uint16_t, dxsm_mixin>  mcg_dxsm_16_8;
typedef mcg_base<uint16_t, uint32_t, dxsm_mixin>  mcg_dxsm_32_16;
typedef mcg_base<uint32_t, uint64_t, dxsm_mixin>  mcg_dxsm_64_32;
typedef mcg_base<uint64_t, pcg128_t, dxsm_mixin>  mcg_dxsm_128_64;
typedef mcg_base<uint64_t, pcg128_t, dxsm_mixin, true, cheap_multiplier>
                                                  cm_mcg_dxsm_128_64;

/* Predefined types for XSL RR (only defined for "large" types) */

typedef oneseq_base<uint32_t, uint64_t, xsl_rr_mixin>  oneseq_xsl_rr_64_32;
typedef oneseq_base<uint64_t, pcg128_t, xsl_rr_mixin>  oneseq_xsl_rr_128_64;
typedef oneseq_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>
                                                       cm_oneseq_xsl_rr_128_64;

typedef unique_base<uint32_t, uint64_t, xsl_rr_mixin>  unique_xsl_rr_64_32;
typedef unique_base<uint64_t, pcg128_t, xsl_rr_mixin>  unique_xsl_rr_128_64;
typedef unique_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>
                                                       cm_unique_xsl_rr_128_64;

typedef setseq_base<uint32_t, uint64_t, xsl_rr_mixin>  setseq_xsl_rr_64_32;
typedef setseq_base<uint64_t, pcg128_t, xsl_rr_mixin>  setseq_xsl_rr_128_64;
typedef setseq_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>
                                                       cm_setseq_xsl_rr_128_64;

typedef mcg_base<uint32_t, uint64_t, xsl_rr_mixin>  mcg_xsl_rr_64_32;
typedef mcg_base<uint64_t, pcg128_t, xsl_rr_mixin>  mcg_xsl_rr_128_64;
typedef mcg_base<uint64_t, pcg128_t, xsl_rr_mixin, true, cheap_multiplier>
                                                    cm_mcg_xsl_rr_128_64;


/* Predefined types for XSL RR RR (only defined for "large" types) */

typedef oneseq_base<uint64_t, uint64_t, xsl_rr_rr_mixin>
    oneseq_xsl_rr_rr_64_64;
typedef oneseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin>
    oneseq_xsl_rr_rr_128_128;
typedef oneseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin, true, cheap_multiplier>
    cm_oneseq_xsl_rr_rr_128_128;

typedef unique_base<uint64_t, uint64_t, xsl_rr_rr_mixin>
    unique_xsl_rr_rr_64_64;
typedef unique_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin>
    unique_xsl_rr_rr_128_128;
typedef unique_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin, true, cheap_multiplier>
    cm_unique_xsl_rr_rr_128_128;

typedef setseq_base<uint64_t, uint64_t, xsl_rr_rr_mixin>
    setseq_xsl_rr_rr_64_64;
typedef setseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin>
    setseq_xsl_rr_rr_128_128;
typedef setseq_base<pcg128_t, pcg128_t, xsl_rr_rr_mixin, true, cheap_multiplier>
    cm_setseq_xsl_rr_rr_128_128;

                // MCG versions don't make sense here, so aren't defined.

/* Extended generators */

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename BaseRNG, bool kdd = true>
using ext_std8 = pcg_extended<table_pow2, advance_pow2, BaseRNG,
                          oneseq_rxs_m_xs_8_8, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename BaseRNG, bool kdd = true>
using ext_std16 = pcg_extended<table_pow2, advance_pow2, BaseRNG,
                           oneseq_rxs_m_xs_16_16, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename BaseRNG, bool kdd = true>
using ext_std32 = pcg_extended<table_pow2, advance_pow2, BaseRNG,
                           oneseq_rxs_m_xs_32_32, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2,
          typename BaseRNG, bool kdd = true>
using ext_std64 = pcg_extended<table_pow2, advance_pow2, BaseRNG,
                           oneseq_rxs_m_xs_64_64, kdd>;


template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>
using ext_oneseq_rxs_m_xs_32_32 =
          ext_std32<table_pow2, advance_pow2, oneseq_rxs_m_xs_32_32, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>
using ext_mcg_xsh_rs_64_32 =
          ext_std32<table_pow2, advance_pow2, mcg_xsh_rs_64_32, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>
using ext_oneseq_xsh_rs_64_32 =
          ext_std32<table_pow2, advance_pow2, oneseq_xsh_rs_64_32, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>
using ext_setseq_xsh_rr_64_32 =
          ext_std32<table_pow2, advance_pow2, setseq_xsh_rr_64_32, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>
using ext_mcg_xsl_rr_128_64 =
          ext_std64<table_pow2, advance_pow2, mcg_xsl_rr_128_64, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>
using ext_oneseq_xsl_rr_128_64 =
          ext_std64<table_pow2, advance_pow2, oneseq_xsl_rr_128_64, kdd>;

template <bitcount_t table_pow2, bitcount_t advance_pow2, bool kdd = true>
using ext_setseq_xsl_rr_128_64 =
          ext_std64<table_pow2, advance_pow2, setseq_xsl_rr_128_64, kdd>;

} // namespace pcg_engines

typedef pcg_engines::setseq_xsh_rr_64_32        pcg32;
typedef pcg_engines::oneseq_xsh_rr_64_32        pcg32_oneseq;
typedef pcg_engines::unique_xsh_rr_64_32        pcg32_unique;
typedef pcg_engines::mcg_xsh_rs_64_32           pcg32_fast;

typedef pcg_engines::setseq_xsl_rr_128_64       pcg64;
typedef pcg_engines::oneseq_xsl_rr_128_64       pcg64_oneseq;
typedef pcg_engines::unique_xsl_rr_128_64       pcg64_unique;
typedef pcg_engines::mcg_xsl_rr_128_64          pcg64_fast;

typedef pcg_engines::setseq_rxs_m_xs_8_8        pcg8_once_insecure;
typedef pcg_engines::setseq_rxs_m_xs_16_16      pcg16_once_insecure;
typedef pcg_engines::setseq_rxs_m_xs_32_32      pcg32_once_insecure;
typedef pcg_engines::setseq_rxs_m_xs_64_64      pcg64_once_insecure;
typedef pcg_engines::setseq_xsl_rr_rr_128_128   pcg128_once_insecure;

typedef pcg_engines::oneseq_rxs_m_xs_8_8        pcg8_oneseq_once_insecure;
typedef pcg_engines::oneseq_rxs_m_xs_16_16      pcg16_oneseq_once_insecure;
typedef pcg_engines::oneseq_rxs_m_xs_32_32      pcg32_oneseq_once_insecure;
typedef pcg_engines::oneseq_rxs_m_xs_64_64      pcg64_oneseq_once_insecure;
typedef pcg_engines::oneseq_xsl_rr_rr_128_128   pcg128_oneseq_once_insecure;


// These two extended RNGs provide two-dimensionally equidistributed
// 32-bit generators.  pcg32_k2_fast occupies the same space as pcg64,
// and can be called twice to generate 64 bits, but does not required
// 128-bit math; on 32-bit systems, it's faster than pcg64 as well.

typedef pcg_engines::ext_setseq_xsh_rr_64_32<1,16,true>     pcg32_k2;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<1,32,true>     pcg32_k2_fast;

// These eight extended RNGs have about as much state as arc4random
//
//  - the k variants are k-dimensionally equidistributed
//  - the c variants offer better crypographic security
//
// (just how good the cryptographic security is is an open question)

typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,true>     pcg32_k64;
typedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,true>        pcg32_k64_oneseq;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,true>     pcg32_k64_fast;

typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,false>    pcg32_c64;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,false>    pcg32_c64_oneseq;
typedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,false>       pcg32_c64_fast;

typedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,true>    pcg64_k32;
typedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,true>   pcg64_k32_oneseq;
typedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,true>      pcg64_k32_fast;

typedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,false>   pcg64_c32;
typedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,false>  pcg64_c32_oneseq;
typedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,false>     pcg64_c32_fast;

// These eight extended RNGs have more state than the Mersenne twister
//
//  - the k variants are k-dimensionally equidistributed
//  - the c variants offer better crypographic security
//
// (just how good the cryptographic security is is an open question)

typedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,true>    pcg32_k1024;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,true>    pcg32_k1024_fast;

typedef pcg_engines::ext_setseq_xsh_rr_64_32<10,16,false>   pcg32_c1024;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<10,32,false>   pcg32_c1024_fast;

typedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,true>   pcg64_k1024;
typedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,true>  pcg64_k1024_fast;

typedef pcg_engines::ext_setseq_xsl_rr_128_64<10,16,false>  pcg64_c1024;
typedef pcg_engines::ext_oneseq_xsl_rr_128_64<10,128,false> pcg64_c1024_fast;

// These generators have an insanely huge period (2^524352), and is suitable
// for silly party tricks, such as dumping out 64 KB ZIP files at an arbitrary
// point in the future.   [Actually, over the full period of the generator, it
// will produce every 64 KB ZIP file 2^64 times!]

typedef pcg_engines::ext_setseq_xsh_rr_64_32<14,16,true>    pcg32_k16384;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<14,32,true>    pcg32_k16384_fast;

#ifdef _MSC_VER
    #pragma warning(default:4146)
#endif

#endif // PCG_RAND_HPP_INCLUDED


// LICENSE_CHANGE_END
// RE2 compatibility layer with std::regex




#include <vector>
#include <string>
#include <stdexcept>

namespace duckdb_re2 {
class RE2;

enum class RegexOptions : uint8_t { NONE, CASE_INSENSITIVE };

class Regex {
public:
	DUCKDB_API Regex(const std::string &pattern, RegexOptions options = RegexOptions::NONE);
	DUCKDB_API Regex(const char *pattern, RegexOptions options = RegexOptions::NONE) : Regex(std::string(pattern)) {
	}
	const duckdb_re2::RE2 &GetRegex() const {
		return *regex;
	}

private:
	std::shared_ptr<duckdb_re2::RE2> regex;
};

struct GroupMatch {
	std::string text;
	uint32_t position;

	const std::string &str() const {
		return text;
	}
	operator std::string() const {
		return text;
	}
};

struct Match {
	std::vector<GroupMatch> groups;

	GroupMatch &GetGroup(uint64_t index) {
		if (index >= groups.size()) {
			throw std::runtime_error("RE2: Match index is out of range");
		}
		return groups[index];
	}

	std::string str(uint64_t index) {
		return GetGroup(index).text;
	}

	uint64_t position(uint64_t index) {
		return GetGroup(index).position;
	}

	uint64_t length(uint64_t index) {
		return GetGroup(index).text.size();
	}

	GroupMatch &operator[](uint64_t i) {
		return GetGroup(i);
	}
};

DUCKDB_API bool RegexSearch(const std::string &input, Match &match, const Regex &regex);
DUCKDB_API bool RegexMatch(const std::string &input, Match &match, const Regex &regex);
DUCKDB_API bool RegexMatch(const char *start, const char *end, Match &match, const Regex &regex);
DUCKDB_API bool RegexMatch(const std::string &input, const Regex &regex);
DUCKDB_API std::vector<Match> RegexFindAll(const std::string &input, const Regex &regex);

} // namespace duckdb_re2


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #6
// See the end of this file for a list

// Copyright 2003-2009 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef RE2_RE2_H_
#define RE2_RE2_H_

// C++ interface to the re2 regular-expression library.
// RE2 supports Perl-style regular expressions (with extensions like
// \d, \w, \s, ...).
//
// -----------------------------------------------------------------------
// REGEXP SYNTAX:
//
// This module uses the re2 library and hence supports
// its syntax for regular expressions, which is similar to Perl's with
// some of the more complicated things thrown away.  In particular,
// backreferences and generalized assertions are not available, nor is \Z.
//
// See https://github.com/google/re2/wiki/Syntax for the syntax
// supported by RE2, and a comparison with PCRE and PERL regexps.
//
// For those not familiar with Perl's regular expressions,
// here are some examples of the most commonly used extensions:
//
//   "hello (\\w+) world"  -- \w matches a "word" character
//   "version (\\d+)"      -- \d matches a digit
//   "hello\\s+world"      -- \s matches any whitespace character
//   "\\b(\\w+)\\b"        -- \b matches non-empty string at word boundary
//   "(?i)hello"           -- (?i) turns on case-insensitive matching
//   "/\\*(.*?)\\*/"       -- .*? matches . minimum no. of times possible
//
// -----------------------------------------------------------------------
// MATCHING INTERFACE:
//
// The "FullMatch" operation checks that supplied text matches a
// supplied pattern exactly.
//
// Example: successful match
//    CHECK(RE2::FullMatch("hello", "h.*o"));
//
// Example: unsuccessful match (requires full match):
//    CHECK(!RE2::FullMatch("hello", "e"));
//
// -----------------------------------------------------------------------
// UTF-8 AND THE MATCHING INTERFACE:
//
// By default, the pattern and input text are interpreted as UTF-8.
// The RE2::Latin1 option causes them to be interpreted as Latin-1.
//
// Example:
//    CHECK(RE2::FullMatch(utf8_string, RE2(utf8_pattern)));
//    CHECK(RE2::FullMatch(latin1_string, RE2(latin1_pattern, RE2::Latin1)));
//
// -----------------------------------------------------------------------
// MATCHING WITH SUBSTRING EXTRACTION:
//
// You can supply extra pointer arguments to extract matched substrings.
// On match failure, none of the pointees will have been modified.
// On match success, the substrings will be converted (as necessary) and
// their values will be assigned to their pointees until all conversions
// have succeeded or one conversion has failed.
// On conversion failure, the pointees will be in an indeterminate state
// because the caller has no way of knowing which conversion failed.
// However, conversion cannot fail for types like string and StringPiece
// that do not inspect the substring contents. Hence, in the common case
// where all of the pointees are of such types, failure is always due to
// match failure and thus none of the pointees will have been modified.
//
// Example: extracts "ruby" into "s" and 1234 into "i"
//    int i;
//    std::string s;
//    CHECK(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", &s, &i));
//
// Example: fails because string cannot be stored in integer
//    CHECK(!RE2::FullMatch("ruby", "(.*)", &i));
//
// Example: fails because there aren't enough sub-patterns
//    CHECK(!RE2::FullMatch("ruby:1234", "\\w+:\\d+", &s));
//
// Example: does not try to extract any extra sub-patterns
//    CHECK(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", &s));
//
// Example: does not try to extract into NULL
//    CHECK(RE2::FullMatch("ruby:1234", "(\\w+):(\\d+)", NULL, &i));
//
// Example: integer overflow causes failure
//    CHECK(!RE2::FullMatch("ruby:1234567891234", "\\w+:(\\d+)", &i));
//
// NOTE(rsc): Asking for substrings slows successful matches quite a bit.
// This may get a little faster in the future, but right now is slower
// than PCRE.  On the other hand, failed matches run *very* fast (faster
// than PCRE), as do matches without substring extraction.
//
// -----------------------------------------------------------------------
// PARTIAL MATCHES
//
// You can use the "PartialMatch" operation when you want the pattern
// to match any substring of the text.
//
// Example: simple search for a string:
//      CHECK(RE2::PartialMatch("hello", "ell"));
//
// Example: find first number in a string
//      int number;
//      CHECK(RE2::PartialMatch("x*100 + 20", "(\\d+)", &number));
//      CHECK_EQ(number, 100);
//
// -----------------------------------------------------------------------
// PRE-COMPILED REGULAR EXPRESSIONS
//
// RE2 makes it easy to use any string as a regular expression, without
// requiring a separate compilation step.
//
// If speed is of the essence, you can create a pre-compiled "RE2"
// object from the pattern and use it multiple times.  If you do so,
// you can typically parse text faster than with sscanf.
//
// Example: precompile pattern for faster matching:
//    RE2 pattern("h.*o");
//    while (ReadLine(&str)) {
//      if (RE2::FullMatch(str, pattern)) ...;
//    }
//
// -----------------------------------------------------------------------
// SCANNING TEXT INCREMENTALLY
//
// The "Consume" operation may be useful if you want to repeatedly
// match regular expressions at the front of a string and skip over
// them as they match.  This requires use of the "StringPiece" type,
// which represents a sub-range of a real string.
//
// Example: read lines of the form "var = value" from a string.
//      std::string contents = ...;     // Fill string somehow
//      StringPiece input(contents);    // Wrap a StringPiece around it
//
//      std::string var;
//      int value;
//      while (RE2::Consume(&input, "(\\w+) = (\\d+)\n", &var, &value)) {
//        ...;
//      }
//
// Each successful call to "Consume" will set "var/value", and also
// advance "input" so it points past the matched text.  Note that if the
// regular expression matches an empty string, input will advance
// by 0 bytes.  If the regular expression being used might match
// an empty string, the loop body must check for this case and either
// advance the string or break out of the loop.
//
// The "FindAndConsume" operation is similar to "Consume" but does not
// anchor your match at the beginning of the string.  For example, you
// could extract all words from a string by repeatedly calling
//     RE2::FindAndConsume(&input, "(\\w+)", &word)
//
// -----------------------------------------------------------------------
// USING VARIABLE NUMBER OF ARGUMENTS
//
// The above operations require you to know the number of arguments
// when you write the code.  This is not always possible or easy (for
// example, the regular expression may be calculated at run time).
// You can use the "N" version of the operations when the number of
// match arguments are determined at run time.
//
// Example:
//   const RE2::Arg* args[10];
//   int n;
//   // ... populate args with pointers to RE2::Arg values ...
//   // ... set n to the number of RE2::Arg objects ...
//   bool match = RE2::FullMatchN(input, pattern, args, n);
//
// The last statement is equivalent to
//
//   bool match = RE2::FullMatch(input, pattern,
//                               *args[0], *args[1], ..., *args[n - 1]);
//
// -----------------------------------------------------------------------
// PARSING HEX/OCTAL/C-RADIX NUMBERS
//
// By default, if you pass a pointer to a numeric value, the
// corresponding text is interpreted as a base-10 number.  You can
// instead wrap the pointer with a call to one of the operators Hex(),
// Octal(), or CRadix() to interpret the text in another base.  The
// CRadix operator interprets C-style "0" (base-8) and "0x" (base-16)
// prefixes, but defaults to base-10.
//
// Example:
//   int a, b, c, d;
//   CHECK(RE2::FullMatch("100 40 0100 0x40", "(.*) (.*) (.*) (.*)",
//         RE2::Octal(&a), RE2::Hex(&b), RE2::CRadix(&c), RE2::CRadix(&d));
// will leave 64 in a, b, c, and d.

#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <map>
#include <mutex>
#include <string>



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #6
// See the end of this file for a list

// Copyright 2001-2010 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef RE2_STRINGPIECE_H_
#define RE2_STRINGPIECE_H_

#ifdef min
#undef min
#endif

// A string-like object that points to a sized piece of memory.
//
// Functions or methods may use const StringPiece& parameters to accept either
// a "const char*" or a "string" value that will be implicitly converted to
// a StringPiece.  The implicit conversion means that it is often appropriate
// to include this .h file in other files rather than forward-declaring
// StringPiece as would be appropriate for most other Google classes.
//
// Systematic usage of StringPiece is encouraged as it will reduce unnecessary
// conversions from "const char*" to "string" and back again.
//
//
// Arghh!  I wish C++ literals were "string".

// Doing this simplifies the logic below.
#ifndef __has_include
#define __has_include(x) 0
#endif

#include <stddef.h>
#include <string.h>
#include <algorithm>
#include <iosfwd>
#include <iterator>
#include <string>
#if __has_include(<string_view>) && __cplusplus >= 201703L
#include <string_view>
#endif

namespace duckdb_re2 {

class StringPiece {
 public:
  typedef std::char_traits<char> traits_type;
  typedef char value_type;
  typedef char* pointer;
  typedef const char* const_pointer;
  typedef char& reference;
  typedef const char& const_reference;
  typedef const char* const_iterator;
  typedef const_iterator iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  typedef const_reverse_iterator reverse_iterator;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
  static const size_type npos = static_cast<size_type>(-1);

  // We provide non-explicit singleton constructors so users can pass
  // in a "const char*" or a "string" wherever a "StringPiece" is
  // expected.
  StringPiece()
      : data_(NULL), size_(0) {}
#if __has_include(<string_view>) && __cplusplus >= 201703L
  StringPiece(const std::string_view& str)
      : data_(str.data()), size_(str.size()) {}
#endif
  StringPiece(const std::string& str)
      : data_(str.data()), size_(str.size()) {}
  StringPiece(const char* str)
      : data_(str), size_(str == NULL ? 0 : strlen(str)) {}
  StringPiece(const char* str, size_type len)
      : data_(str), size_(len) {}

  const_iterator begin() const { return data_; }
  const_iterator end() const { return data_ + size_; }
  const_reverse_iterator rbegin() const {
    return const_reverse_iterator(data_ + size_);
  }
  const_reverse_iterator rend() const {
    return const_reverse_iterator(data_);
  }

  size_type size() const { return size_; }
  size_type length() const { return size_; }
  bool empty() const { return size_ == 0; }

  const_reference operator[](size_type i) const { return data_[i]; }
  const_pointer data() const { return data_; }

  void remove_prefix(size_type n) {
    data_ += n;
    size_ -= n;
  }

  void remove_suffix(size_type n) {
    size_ -= n;
  }

  void set(const char* str) {
    data_ = str;
    size_ = str == NULL ? 0 : strlen(str);
  }

  void set(const char* str, size_type len) {
    data_ = str;
    size_ = len;
  }

  // Converts to `std::basic_string`.
  template <typename A>
  explicit operator std::basic_string<char, traits_type, A>() const {
    if (!data_) return {};
    return std::basic_string<char, traits_type, A>(data_, size_);
  }

  std::string as_string() const {
    return std::string(data_, size_);
  }

  // We also define ToString() here, since many other string-like
  // interfaces name the routine that converts to a C++ string
  // "ToString", and it's confusing to have the method that does that
  // for a StringPiece be called "as_string()".  We also leave the
  // "as_string()" method defined here for existing code.
  std::string ToString() const {
    return std::string(data_, size_);
  }

  void CopyToString(std::string* target) const {
    target->assign(data_, size_);
  }

  void AppendToString(std::string* target) const {
    target->append(data_, size_);
  }

  size_type copy(char* buf, size_type n, size_type pos = 0) const;
  StringPiece substr(size_type pos = 0, size_type n = npos) const;

  int compare(const StringPiece& x) const {
    size_type min_size = std::min(size(), x.size());
    if (min_size > 0) {
      int r = memcmp(data(), x.data(), min_size);
      if (r < 0) return -1;
      if (r > 0) return 1;
    }
    if (size() < x.size()) return -1;
    if (size() > x.size()) return 1;
    return 0;
  }

  // Does "this" start with "x"?
  bool starts_with(const StringPiece& x) const {
    return x.empty() ||
           (size() >= x.size() && memcmp(data(), x.data(), x.size()) == 0);
  }

  // Does "this" end with "x"?
  bool ends_with(const StringPiece& x) const {
    return x.empty() ||
           (size() >= x.size() &&
            memcmp(data() + (size() - x.size()), x.data(), x.size()) == 0);
  }

  bool contains(const StringPiece& s) const {
    return find(s) != npos;
  }

  size_type find(const StringPiece& s, size_type pos = 0) const;
  size_type find(char c, size_type pos = 0) const;
  size_type rfind(const StringPiece& s, size_type pos = npos) const;
  size_type rfind(char c, size_type pos = npos) const;

 private:
  const_pointer data_;
  size_type size_;
};

inline bool operator==(const StringPiece& x, const StringPiece& y) {
  StringPiece::size_type len = x.size();
  if (len != y.size()) return false;
  return x.data() == y.data() || len == 0 ||
         memcmp(x.data(), y.data(), len) == 0;
}

inline bool operator!=(const StringPiece& x, const StringPiece& y) {
  return !(x == y);
}

inline bool operator<(const StringPiece& x, const StringPiece& y) {
  StringPiece::size_type min_size = std::min(x.size(), y.size());
  int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
  return (r < 0) || (r == 0 && x.size() < y.size());
}

inline bool operator>(const StringPiece& x, const StringPiece& y) {
  return y < x;
}

inline bool operator<=(const StringPiece& x, const StringPiece& y) {
  return !(x > y);
}

inline bool operator>=(const StringPiece& x, const StringPiece& y) {
  return !(x < y);
}

// Allow StringPiece to be logged.
std::ostream& operator<<(std::ostream& o, const StringPiece& p);

}  // namespace duckdb_re2

#endif  // RE2_STRINGPIECE_H_


// LICENSE_CHANGE_END


namespace duckdb_re2 {
class Prog;
class Regexp;
}  // namespace duckdb_re2

namespace duckdb_re2 {

// Interface for regular expression matching.  Also corresponds to a
// pre-compiled regular expression.  An "RE2" object is safe for
// concurrent use by multiple threads.
class RE2 {
 public:
  // We convert user-passed pointers into special Arg objects
  class Arg;
  class Options;

  // Defined in set.h.
  class Set;

  enum ErrorCode {
    NoError = 0,

    // Unexpected error
    ErrorInternal,

    // Parse errors
    ErrorBadEscape,          // bad escape sequence
    ErrorBadCharClass,       // bad character class
    ErrorBadCharRange,       // bad character class range
    ErrorMissingBracket,     // missing closing ]
    ErrorMissingParen,       // missing closing )
    ErrorTrailingBackslash,  // trailing \ at end of regexp
    ErrorRepeatArgument,     // repeat argument missing, e.g. "*"
    ErrorRepeatSize,         // bad repetition argument
    ErrorRepeatOp,           // bad repetition operator
    ErrorBadPerlOp,          // bad perl operator
    ErrorBadUTF8,            // invalid UTF-8 in regexp
    ErrorBadNamedCapture,    // bad named capture group
    ErrorPatternTooLarge     // pattern too large (compile failed)
  };

  // Predefined common options.
  // If you need more complicated things, instantiate
  // an Option class, possibly passing one of these to
  // the Option constructor, change the settings, and pass that
  // Option class to the RE2 constructor.
  enum CannedOptions {
    DefaultOptions = 0,
    Latin1, // treat input as Latin-1 (default UTF-8)
    POSIX, // POSIX syntax, leftmost-longest match
    Quiet // do not log about regexp parse errors
  };

  // Need to have the const char* and const std::string& forms for implicit
  // conversions when passing string literals to FullMatch and PartialMatch.
  // Otherwise the StringPiece form would be sufficient.
#ifndef SWIG
  RE2(const char* pattern);
  RE2(const std::string& pattern);
#endif
  RE2(const StringPiece& pattern);
  RE2(const StringPiece& pattern, const Options& options);
  ~RE2();

  // Returns whether RE2 was created properly.
  bool ok() const { return error_code() == NoError; }

  // The string specification for this RE2.  E.g.
  //   RE2 re("ab*c?d+");
  //   re.pattern();    // "ab*c?d+"
  const std::string& pattern() const { return pattern_; }

  // If RE2 could not be created properly, returns an error string.
  // Else returns the empty string.
  const std::string& error() const { return *error_; }

  // If RE2 could not be created properly, returns an error code.
  // Else returns RE2::NoError (== 0).
  ErrorCode error_code() const { return error_code_; }

  // If RE2 could not be created properly, returns the offending
  // portion of the regexp.
  const std::string& error_arg() const { return error_arg_; }

  // Returns the program size, a very approximate measure of a regexp's "cost".
  // Larger numbers are more expensive than smaller numbers.
  int ProgramSize() const;
  int ReverseProgramSize() const;

  // EXPERIMENTAL! SUBJECT TO CHANGE!
  // Outputs the program fanout as a histogram bucketed by powers of 2.
  // Returns the number of the largest non-empty bucket.
  int ProgramFanout(std::map<int, int>* histogram) const;
  int ReverseProgramFanout(std::map<int, int>* histogram) const;

  // Returns the underlying Regexp; not for general use.
  // Returns entire_regexp_ so that callers don't need
  // to know about prefix_ and prefix_foldcase_.
  duckdb_re2::Regexp* Regexp() const { return entire_regexp_; }

  /***** The array-based matching interface ******/

  // The functions here have names ending in 'N' and are used to implement
  // the functions whose names are the prefix before the 'N'. It is sometimes
  // useful to invoke them directly, but the syntax is awkward, so the 'N'-less
  // versions should be preferred.
  static bool FullMatchN(const StringPiece& text, const RE2& re,
                         const Arg* const args[], int n);
  static bool PartialMatchN(const StringPiece& text, const RE2& re,
                            const Arg* const args[], int n);
  static bool ConsumeN(StringPiece* input, const RE2& re,
                       const Arg* const args[], int n);
  static bool FindAndConsumeN(StringPiece* input, const RE2& re,
                              const Arg* const args[], int n);

#ifndef SWIG
 private:
  template <typename F, typename SP>
  static inline bool Apply(F f, SP sp, const RE2& re) {
    return f(sp, re, NULL, 0);
  }

  template <typename F, typename SP, typename... A>
  static inline bool Apply(F f, SP sp, const RE2& re, const A&... a) {
    const Arg* const args[] = {&a...};
    const int n = sizeof...(a);
    return f(sp, re, args, n);
  }

 public:
  // In order to allow FullMatch() et al. to be called with a varying number
  // of arguments of varying types, we use two layers of variadic templates.
  // The first layer constructs the temporary Arg objects. The second layer
  // (above) constructs the array of pointers to the temporary Arg objects.

  /***** The useful part: the matching interface *****/

  // Matches "text" against "re".  If pointer arguments are
  // supplied, copies matched sub-patterns into them.
  //
  // You can pass in a "const char*" or a "std::string" for "text".
  // You can pass in a "const char*" or a "std::string" or a "RE2" for "re".
  //
  // The provided pointer arguments can be pointers to any scalar numeric
  // type, or one of:
  //    std::string     (matched piece is copied to string)
  //    StringPiece     (StringPiece is mutated to point to matched piece)
  //    T               (where "bool T::ParseFrom(const char*, size_t)" exists)
  //    (void*)NULL     (the corresponding matched sub-pattern is not copied)
  //
  // Returns true iff all of the following conditions are satisfied:
  //   a. "text" matches "re" exactly
  //   b. The number of matched sub-patterns is >= number of supplied pointers
  //   c. The "i"th argument has a suitable type for holding the
  //      string captured as the "i"th sub-pattern.  If you pass in
  //      NULL for the "i"th argument, or pass fewer arguments than
  //      number of sub-patterns, "i"th captured sub-pattern is
  //      ignored.
  //
  // CAVEAT: An optional sub-pattern that does not exist in the
  // matched string is assigned the empty string.  Therefore, the
  // following will return false (because the empty string is not a
  // valid number):
  //    int number;
  //    RE2::FullMatch("abc", "[a-z]+(\\d+)?", &number);
  template <typename... A>
  static bool FullMatch(const StringPiece& text, const RE2& re, A&&... a) {
    return Apply(FullMatchN, text, re, Arg(std::forward<A>(a))...);
  }

  // Exactly like FullMatch(), except that "re" is allowed to match
  // a substring of "text".
  template <typename... A>
  static bool PartialMatch(const StringPiece& text, const RE2& re, A&&... a) {
    return Apply(PartialMatchN, text, re, Arg(std::forward<A>(a))...);
  }

  // Like FullMatch() and PartialMatch(), except that "re" has to match
  // a prefix of the text, and "input" is advanced past the matched
  // text.  Note: "input" is modified iff this routine returns true
  // and "re" matched a non-empty substring of "text".
  template <typename... A>
  static bool Consume(StringPiece* input, const RE2& re, A&&... a) {
    return Apply(ConsumeN, input, re, Arg(std::forward<A>(a))...);
  }

  // Like Consume(), but does not anchor the match at the beginning of
  // the text.  That is, "re" need not start its match at the beginning
  // of "input".  For example, "FindAndConsume(s, "(\\w+)", &word)" finds
  // the next word in "s" and stores it in "word".
  template <typename... A>
  static bool FindAndConsume(StringPiece* input, const RE2& re, A&&... a) {
    return Apply(FindAndConsumeN, input, re, Arg(std::forward<A>(a))...);
  }
#endif

  // Replace the first match of "re" in "str" with "rewrite".
  // Within "rewrite", backslash-escaped digits (\1 to \9) can be
  // used to insert text matching corresponding parenthesized group
  // from the pattern.  \0 in "rewrite" refers to the entire matching
  // text.  E.g.,
  //
  //   std::string s = "yabba dabba doo";
  //   CHECK(RE2::Replace(&s, "b+", "d"));
  //
  // will leave "s" containing "yada dabba doo"
  //
  // Returns true if the pattern matches and a replacement occurs,
  // false otherwise.
  static bool Replace(std::string* str,
                      const RE2& re,
                      const StringPiece& rewrite);

  // Like Replace(), except replaces successive non-overlapping occurrences
  // of the pattern in the string with the rewrite. E.g.
  //
  //   std::string s = "yabba dabba doo";
  //   CHECK(RE2::GlobalReplace(&s, "b+", "d"));
  //
  // will leave "s" containing "yada dada doo"
  // Replacements are not subject to re-matching.
  //
  // Because GlobalReplace only replaces non-overlapping matches,
  // replacing "ana" within "banana" makes only one replacement, not two.
  //
  // Returns the number of replacements made.
  static int GlobalReplace(std::string* str,
                           const RE2& re,
                           const StringPiece& rewrite);

  // Like Replace, except that if the pattern matches, "rewrite"
  // is copied into "out" with substitutions.  The non-matching
  // portions of "text" are ignored.
  //
  // Returns true iff a match occurred and the extraction happened
  // successfully;  if no match occurs, the string is left unaffected.
  //
  // REQUIRES: "text" must not alias any part of "*out".
  static bool Extract(const StringPiece& text,
                      const RE2& re,
                      const StringPiece& rewrite,
                      std::string* out);

  // Escapes all potentially meaningful regexp characters in
  // 'unquoted'.  The returned string, used as a regular expression,
  // will exactly match the original string.  For example,
  //           1.5-2.0?
  // may become:
  //           1\.5\-2\.0\?
  static std::string QuoteMeta(const StringPiece& unquoted);

  // Computes range for any strings matching regexp. The min and max can in
  // some cases be arbitrarily precise, so the caller gets to specify the
  // maximum desired length of string returned.
  //
  // Assuming PossibleMatchRange(&min, &max, N) returns successfully, any
  // string s that is an anchored match for this regexp satisfies
  //   min <= s && s <= max.
  //
  // Note that PossibleMatchRange() will only consider the first copy of an
  // infinitely repeated element (i.e., any regexp element followed by a '*' or
  // '+' operator). Regexps with "{N}" constructions are not affected, as those
  // do not compile down to infinite repetitions.
  //
  // Returns true on success, false on error.
  bool PossibleMatchRange(std::string* min, std::string* max,
                          int maxlen) const;

  // Generic matching interface

  // Type of match.
  enum Anchor {
    UNANCHORED,         // No anchoring
    ANCHOR_START,       // Anchor at start only
    ANCHOR_BOTH         // Anchor at start and end
  };

  // Return the number of capturing subpatterns, or -1 if the
  // regexp wasn't valid on construction.  The overall match ($0)
  // does not count: if the regexp is "(a)(b)", returns 2.
  int NumberOfCapturingGroups() const { return num_captures_; }

  // Return a map from names to capturing indices.
  // The map records the index of the leftmost group
  // with the given name.
  // Only valid until the re is deleted.
  const std::map<std::string, int>& NamedCapturingGroups() const;

  // Return a map from capturing indices to names.
  // The map has no entries for unnamed groups.
  // Only valid until the re is deleted.
  const std::map<int, std::string>& CapturingGroupNames() const;

  // General matching routine.
  // Match against text starting at offset startpos
  // and stopping the search at offset endpos.
  // Returns true if match found, false if not.
  // On a successful match, fills in submatch[] (up to nsubmatch entries)
  // with information about submatches.
  // I.e. matching RE2("(foo)|(bar)baz") on "barbazbla" will return true, with
  // submatch[0] = "barbaz", submatch[1].data() = NULL, submatch[2] = "bar",
  // submatch[3].data() = NULL, ..., up to submatch[nsubmatch-1].data() = NULL.
  // Caveat: submatch[] may be clobbered even on match failure.
  //
  // Don't ask for more match information than you will use:
  // runs much faster with nsubmatch == 1 than nsubmatch > 1, and
  // runs even faster if nsubmatch == 0.
  // Doesn't make sense to use nsubmatch > 1 + NumberOfCapturingGroups(),
  // but will be handled correctly.
  //
  // Passing text == StringPiece(NULL, 0) will be handled like any other
  // empty string, but note that on return, it will not be possible to tell
  // whether submatch i matched the empty string or did not match:
  // either way, submatch[i].data() == NULL.
  bool Match(const StringPiece& text,
             size_t startpos,
             size_t endpos,
             Anchor re_anchor,
             StringPiece* submatch,
             int nsubmatch) const;

  // Check that the given rewrite string is suitable for use with this
  // regular expression.  It checks that:
  //   * The regular expression has enough parenthesized subexpressions
  //     to satisfy all of the \N tokens in rewrite
  //   * The rewrite string doesn't have any syntax errors.  E.g.,
  //     '\' followed by anything other than a digit or '\'.
  // A true return value guarantees that Replace() and Extract() won't
  // fail because of a bad rewrite string.
  bool CheckRewriteString(const StringPiece& rewrite,
                          std::string* error) const;

  // Returns the maximum submatch needed for the rewrite to be done by
  // Replace(). E.g. if rewrite == "foo \\2,\\1", returns 2.
  static int MaxSubmatch(const StringPiece& rewrite);

  // Append the "rewrite" string, with backslash subsitutions from "vec",
  // to string "out".
  // Returns true on success.  This method can fail because of a malformed
  // rewrite string.  CheckRewriteString guarantees that the rewrite will
  // be sucessful.
  bool Rewrite(std::string* out,
               const StringPiece& rewrite,
               const StringPiece* vec,
               int veclen) const;

  // Constructor options
  class Options {
   public:
    // The options are (defaults in parentheses):
    //
    //   utf8             (true)  text and pattern are UTF-8; otherwise Latin-1
    //   posix_syntax     (false) restrict regexps to POSIX egrep syntax
    //   longest_match    (false) search for longest match, not first match
    //   log_errors       (true)  log syntax and execution errors to ERROR
    //   max_mem          (see below)  approx. max memory footprint of RE2
    //   literal          (false) interpret string as literal, not regexp
    //   never_nl         (false) never match \n, even if it is in regexp
    //   dot_nl           (false) dot matches everything including new line
    //   never_capture    (false) parse all parens as non-capturing
    //   case_sensitive   (true)  match is case-sensitive (regexp can override
    //                              with (?i) unless in posix_syntax mode)
    //
    // The following options are only consulted when posix_syntax == true.
    // When posix_syntax == false, these features are always enabled and
    // cannot be turned off; to perform multi-line matching in that case,
    // begin the regexp with (?m).
    //   perl_classes     (false) allow Perl's \d \s \w \D \S \W
    //   word_boundary    (false) allow Perl's \b \B (word boundary and not)
    //   one_line         (false) ^ and $ only match beginning and end of text
    //
    // The max_mem option controls how much memory can be used
    // to hold the compiled form of the regexp (the Prog) and
    // its cached DFA graphs.  Code Search placed limits on the number
    // of Prog instructions and DFA states: 10,000 for both.
    // In RE2, those limits would translate to about 240 KB per Prog
    // and perhaps 2.5 MB per DFA (DFA state sizes vary by regexp; RE2 does a
    // better job of keeping them small than Code Search did).
    // Each RE2 has two Progs (one forward, one reverse), and each Prog
    // can have two DFAs (one first match, one longest match).
    // That makes 4 DFAs:
    //
    //   forward, first-match    - used for UNANCHORED or ANCHOR_START searches
    //                               if opt.longest_match() == false
    //   forward, longest-match  - used for all ANCHOR_BOTH searches,
    //                               and the other two kinds if
    //                               opt.longest_match() == true
    //   reverse, first-match    - never used
    //   reverse, longest-match  - used as second phase for unanchored searches
    //
    // The RE2 memory budget is statically divided between the two
    // Progs and then the DFAs: two thirds to the forward Prog
    // and one third to the reverse Prog.  The forward Prog gives half
    // of what it has left over to each of its DFAs.  The reverse Prog
    // gives it all to its longest-match DFA.
    //
    // Once a DFA fills its budget, it flushes its cache and starts over.
    // If this happens too often, RE2 falls back on the NFA implementation.

    // For now, make the default budget something close to Code Search.
    static const int kDefaultMaxMem = 8<<20;

    enum Encoding {
      EncodingUTF8 = 1,
      EncodingLatin1
    };

    Options() :
      encoding_(EncodingUTF8),
      posix_syntax_(false),
      longest_match_(false),
      log_errors_(true),
      max_mem_(kDefaultMaxMem),
      literal_(false),
      never_nl_(false),
      dot_nl_(false),
      never_capture_(false),
      case_sensitive_(true),
      perl_classes_(false),
      word_boundary_(false),
      one_line_(false) {
    }

    /*implicit*/ Options(CannedOptions);

    Encoding encoding() const { return encoding_; }
    void set_encoding(Encoding encoding) { encoding_ = encoding; }

    // Legacy interface to encoding.
    // TODO(rsc): Remove once clients have been converted.
    bool utf8() const { return encoding_ == EncodingUTF8; }
    void set_utf8(bool b) {
      if (b) {
        encoding_ = EncodingUTF8;
      } else {
        encoding_ = EncodingLatin1;
      }
    }

    bool posix_syntax() const { return posix_syntax_; }
    void set_posix_syntax(bool b) { posix_syntax_ = b; }

    bool longest_match() const { return longest_match_; }
    void set_longest_match(bool b) { longest_match_ = b; }

    bool log_errors() const { return log_errors_; }
    void set_log_errors(bool b) { log_errors_ = b; }

    int64_t max_mem() const { return max_mem_; }
    void set_max_mem(int64_t m) { max_mem_ = m; }

    bool literal() const { return literal_; }
    void set_literal(bool b) { literal_ = b; }

    bool never_nl() const { return never_nl_; }
    void set_never_nl(bool b) { never_nl_ = b; }

    bool dot_nl() const { return dot_nl_; }
    void set_dot_nl(bool b) { dot_nl_ = b; }

    bool never_capture() const { return never_capture_; }
    void set_never_capture(bool b) { never_capture_ = b; }

    bool case_sensitive() const { return case_sensitive_; }
    void set_case_sensitive(bool b) { case_sensitive_ = b; }

    bool perl_classes() const { return perl_classes_; }
    void set_perl_classes(bool b) { perl_classes_ = b; }

    bool word_boundary() const { return word_boundary_; }
    void set_word_boundary(bool b) { word_boundary_ = b; }

    bool one_line() const { return one_line_; }
    void set_one_line(bool b) { one_line_ = b; }

    void Copy(const Options& src) {
      *this = src;
    }

    int ParseFlags() const;

   private:
    Encoding encoding_;
    bool posix_syntax_;
    bool longest_match_;
    bool log_errors_;
    int64_t max_mem_;
    bool literal_;
    bool never_nl_;
    bool dot_nl_;
    bool never_capture_;
    bool case_sensitive_;
    bool perl_classes_;
    bool word_boundary_;
    bool one_line_;
  };

  // Returns the options set in the constructor.
  const Options& options() const { return options_; }

  // Argument converters; see below.
  static inline Arg CRadix(short* x);
  static inline Arg CRadix(unsigned short* x);
  static inline Arg CRadix(int* x);
  static inline Arg CRadix(unsigned int* x);
  static inline Arg CRadix(long* x);
  static inline Arg CRadix(unsigned long* x);
  static inline Arg CRadix(long long* x);
  static inline Arg CRadix(unsigned long long* x);

  static inline Arg Hex(short* x);
  static inline Arg Hex(unsigned short* x);
  static inline Arg Hex(int* x);
  static inline Arg Hex(unsigned int* x);
  static inline Arg Hex(long* x);
  static inline Arg Hex(unsigned long* x);
  static inline Arg Hex(long long* x);
  static inline Arg Hex(unsigned long long* x);

  static inline Arg Octal(short* x);
  static inline Arg Octal(unsigned short* x);
  static inline Arg Octal(int* x);
  static inline Arg Octal(unsigned int* x);
  static inline Arg Octal(long* x);
  static inline Arg Octal(unsigned long* x);
  static inline Arg Octal(long long* x);
  static inline Arg Octal(unsigned long long* x);

 private:
  void Init(const StringPiece& pattern, const Options& options);

  bool DoMatch(const StringPiece& text,
               Anchor re_anchor,
               size_t* consumed,
               const Arg* const args[],
               int n) const;

  duckdb_re2::Prog* ReverseProg() const;

  std::string   pattern_;          // string regular expression
  Options       options_;          // option flags
  std::string   prefix_;           // required prefix (before regexp_)
  bool          prefix_foldcase_;  // prefix is ASCII case-insensitive
  duckdb_re2::Regexp*  entire_regexp_;    // parsed regular expression
  duckdb_re2::Regexp*  suffix_regexp_;    // parsed regular expression, prefix removed
  duckdb_re2::Prog*    prog_;             // compiled program for regexp
  int           num_captures_;     // Number of capturing groups
  bool          is_one_pass_;      // can use prog_->SearchOnePass?

  mutable duckdb_re2::Prog*          rprog_;    // reverse program for regexp
  mutable const std::string*  error_;    // Error indicator
                                         // (or points to empty string)
  mutable ErrorCode      error_code_;    // Error code
  mutable std::string    error_arg_;     // Fragment of regexp showing error

  // Map from capture names to indices
  mutable const std::map<std::string, int>* named_groups_;

  // Map from capture indices to names
  mutable const std::map<int, std::string>* group_names_;

  // Onces for lazy computations.
  mutable std::once_flag rprog_once_;
  mutable std::once_flag named_groups_once_;
  mutable std::once_flag group_names_once_;

  RE2(const RE2&) = delete;
  RE2& operator=(const RE2&) = delete;
};

/***** Implementation details *****/

// Hex/Octal/Binary?

// Special class for parsing into objects that define a ParseFrom() method
template <class T>
class _RE2_MatchObject {
 public:
  static inline bool Parse(const char* str, size_t n, void* dest) {
    if (dest == NULL) return true;
    T* object = reinterpret_cast<T*>(dest);
    return object->ParseFrom(str, n);
  }
};

class RE2::Arg {
 public:
  // Empty constructor so we can declare arrays of RE2::Arg
  Arg();

  // Constructor specially designed for NULL arguments
  Arg(void*);
  Arg(std::nullptr_t);

  typedef bool (*Parser)(const char* str, size_t n, void* dest);

// Type-specific parsers
#define MAKE_PARSER(type, name)            \
  Arg(type* p) : arg_(p), parser_(name) {} \
  Arg(type* p, Parser parser) : arg_(p), parser_(parser) {}

  MAKE_PARSER(char,               parse_char)
  MAKE_PARSER(signed char,        parse_schar)
  MAKE_PARSER(unsigned char,      parse_uchar)
  MAKE_PARSER(float,              parse_float)
  MAKE_PARSER(double,             parse_double)
  MAKE_PARSER(std::string,        parse_string)
  MAKE_PARSER(StringPiece,        parse_stringpiece)

  MAKE_PARSER(short,              parse_short)
  MAKE_PARSER(unsigned short,     parse_ushort)
  MAKE_PARSER(int,                parse_int)
  MAKE_PARSER(unsigned int,       parse_uint)
  MAKE_PARSER(long,               parse_long)
  MAKE_PARSER(unsigned long,      parse_ulong)
  MAKE_PARSER(long long,          parse_longlong)
  MAKE_PARSER(unsigned long long, parse_ulonglong)

#undef MAKE_PARSER

  // Generic constructor templates
  template <class T> Arg(T* p)
      : arg_(p), parser_(_RE2_MatchObject<T>::Parse) { }
  template <class T> Arg(T* p, Parser parser)
      : arg_(p), parser_(parser) { }

  // Parse the data
  bool Parse(const char* str, size_t n) const;

 private:
  void*         arg_;
  Parser        parser_;

  static bool parse_null          (const char* str, size_t n, void* dest);
  static bool parse_char          (const char* str, size_t n, void* dest);
  static bool parse_schar         (const char* str, size_t n, void* dest);
  static bool parse_uchar         (const char* str, size_t n, void* dest);
  static bool parse_float         (const char* str, size_t n, void* dest);
  static bool parse_double        (const char* str, size_t n, void* dest);
  static bool parse_string        (const char* str, size_t n, void* dest);
  static bool parse_stringpiece   (const char* str, size_t n, void* dest);

#define DECLARE_INTEGER_PARSER(name)                                       \
 private:                                                                  \
  static bool parse_##name(const char* str, size_t n, void* dest);         \
  static bool parse_##name##_radix(const char* str, size_t n, void* dest,  \
                                   int radix);                             \
                                                                           \
 public:                                                                   \
  static bool parse_##name##_hex(const char* str, size_t n, void* dest);   \
  static bool parse_##name##_octal(const char* str, size_t n, void* dest); \
  static bool parse_##name##_cradix(const char* str, size_t n, void* dest);

  DECLARE_INTEGER_PARSER(short)
  DECLARE_INTEGER_PARSER(ushort)
  DECLARE_INTEGER_PARSER(int)
  DECLARE_INTEGER_PARSER(uint)
  DECLARE_INTEGER_PARSER(long)
  DECLARE_INTEGER_PARSER(ulong)
  DECLARE_INTEGER_PARSER(longlong)
  DECLARE_INTEGER_PARSER(ulonglong)

#undef DECLARE_INTEGER_PARSER

};

inline RE2::Arg::Arg() : arg_(NULL), parser_(parse_null) { }
inline RE2::Arg::Arg(void* p) : arg_(p), parser_(parse_null) { }
inline RE2::Arg::Arg(std::nullptr_t p) : arg_(p), parser_(parse_null) { }

inline bool RE2::Arg::Parse(const char* str, size_t n) const {
  return (*parser_)(str, n, arg_);
}

// This part of the parser, appropriate only for ints, deals with bases
#define MAKE_INTEGER_PARSER(type, name)                    \
  inline RE2::Arg RE2::Hex(type* ptr) {                    \
    return RE2::Arg(ptr, RE2::Arg::parse_##name##_hex);    \
  }                                                        \
  inline RE2::Arg RE2::Octal(type* ptr) {                  \
    return RE2::Arg(ptr, RE2::Arg::parse_##name##_octal);  \
  }                                                        \
  inline RE2::Arg RE2::CRadix(type* ptr) {                 \
    return RE2::Arg(ptr, RE2::Arg::parse_##name##_cradix); \
  }

MAKE_INTEGER_PARSER(short,              short)
MAKE_INTEGER_PARSER(unsigned short,     ushort)
MAKE_INTEGER_PARSER(int,                int)
MAKE_INTEGER_PARSER(unsigned int,       uint)
MAKE_INTEGER_PARSER(long,               long)
MAKE_INTEGER_PARSER(unsigned long,      ulong)
MAKE_INTEGER_PARSER(long long,          longlong)
MAKE_INTEGER_PARSER(unsigned long long, ulonglong)

#undef MAKE_INTEGER_PARSER

#ifndef SWIG


// Helper for writing global or static RE2s safely.
// Write
//     static LazyRE2 re = {".*"};
// and then use *re instead of writing
//     static RE2 re(".*");
// The former is more careful about multithreaded
// situations than the latter.
//
// N.B. This class never deletes the RE2 object that
// it constructs: that's a feature, so that it can be used
// for global and function static variables.
class LazyRE2 {
 private:
  struct NoArg {};

 public:
  typedef RE2 element_type;  // support std::pointer_traits

  // Constructor omitted to preserve braced initialization in C++98.

  // Pretend to be a pointer to Type (never NULL due to on-demand creation):
  RE2& operator*() const { return *get(); }
  RE2* operator->() const { return get(); }

  // Named accessor/initializer:
  RE2* get() const {
    std::call_once(once_, &LazyRE2::Init, this);
    return ptr_;
  }

  // All data fields must be public to support {"foo"} initialization.
  const char* pattern_;
  RE2::CannedOptions options_;
  NoArg barrier_against_excess_initializers_;

  mutable RE2* ptr_;
  mutable std::once_flag once_;

 private:
  static void Init(const LazyRE2* lazy_re2) {
    lazy_re2->ptr_ = new RE2(lazy_re2->pattern_, lazy_re2->options_);
  }

  void operator=(const LazyRE2&);  // disallowed
};
#endif  // SWIG

}  // namespace duckdb_re2

using duckdb_re2::RE2;
using duckdb_re2::LazyRE2;

#endif  // RE2_RE2_H_


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






namespace duckdb {

struct AggregateObject;
struct AggregateFilterData;
class DataChunk;
class RowLayout;
class RowDataCollection;
struct SelectionVector;
class StringHeap;
class Vector;
struct VectorData;

// RowOperations contains a set of operations that operate on data using a RowLayout
struct RowOperations {
	//===--------------------------------------------------------------------===//
	// Aggregation Operators
	//===--------------------------------------------------------------------===//
	//! initialize - unaligned addresses
	static void InitializeStates(RowLayout &layout, Vector &addresses, const SelectionVector &sel, idx_t count);
	//! destructor - unaligned addresses, updated
	static void DestroyStates(RowLayout &layout, Vector &addresses, idx_t count);
	//! update - aligned addresses
	static void UpdateStates(AggregateObject &aggr, Vector &addresses, DataChunk &payload, idx_t arg_idx, idx_t count);
	//! filtered update - aligned addresses
	static void UpdateFilteredStates(AggregateFilterData &filter_data, AggregateObject &aggr, Vector &addresses,
	                                 DataChunk &payload, idx_t arg_idx);
	//! combine - unaligned addresses, updated
	static void CombineStates(RowLayout &layout, Vector &sources, Vector &targets, idx_t count);
	//! finalize - unaligned addresses, updated
	static void FinalizeStates(RowLayout &layout, Vector &addresses, DataChunk &result, idx_t aggr_idx);

	//===--------------------------------------------------------------------===//
	// Read/Write Operators
	//===--------------------------------------------------------------------===//
	//! Scatter group data to the rows. Initialises the ValidityMask.
	static void Scatter(DataChunk &columns, VectorData col_data[], const RowLayout &layout, Vector &rows,
	                    RowDataCollection &string_heap, const SelectionVector &sel, idx_t count);
	//! Gather a single column.
	static void Gather(Vector &rows, const SelectionVector &row_sel, Vector &col, const SelectionVector &col_sel,
	                   const idx_t count, const idx_t col_offset, const idx_t col_no, const idx_t build_size = 0);
	//! Full Scan an entire columns
	static void FullScanColumn(const RowLayout &layout, Vector &rows, Vector &col, idx_t count, idx_t col_idx);

	//===--------------------------------------------------------------------===//
	// Comparison Operators
	//===--------------------------------------------------------------------===//
	//! Compare a block of key data against the row values to produce an updated selection that matches
	//! and a second (optional) selection of non-matching values.
	//! Returns the number of matches remaining in the selection.
	using Predicates = vector<ExpressionType>;

	static idx_t Match(DataChunk &columns, VectorData col_data[], const RowLayout &layout, Vector &rows,
	                   const Predicates &predicates, SelectionVector &sel, idx_t count, SelectionVector *no_match,
	                   idx_t &no_match_count);

	//===--------------------------------------------------------------------===//
	// Heap Operators
	//===--------------------------------------------------------------------===//
	//! Compute the entry sizes of a vector with variable size type (used before building heap buffer space).
	static void ComputeEntrySizes(Vector &v, idx_t entry_sizes[], idx_t vcount, idx_t ser_count,
	                              const SelectionVector &sel, idx_t offset = 0);
	//! Compute the entry sizes of vector data with variable size type (used before building heap buffer space).
	static void ComputeEntrySizes(Vector &v, VectorData &vdata, idx_t entry_sizes[], idx_t vcount, idx_t ser_count,
	                              const SelectionVector &sel, idx_t offset = 0);
	//! Scatter vector with variable size type to the heap.
	static void HeapScatter(Vector &v, idx_t vcount, const SelectionVector &sel, idx_t ser_count, idx_t col_idx,
	                        data_ptr_t *key_locations, data_ptr_t *validitymask_locations, idx_t offset = 0);
	//! Scatter vector data with variable size type to the heap.
	static void HeapScatterVData(VectorData &vdata, PhysicalType type, const SelectionVector &sel, idx_t ser_count,
	                             idx_t col_idx, data_ptr_t *key_locations, data_ptr_t *validitymask_locations,
	                             idx_t offset = 0);
	//! Gather a single column with variable size type from the heap.
	static void HeapGather(Vector &v, const idx_t &vcount, const SelectionVector &sel, const idx_t &col_idx,
	                       data_ptr_t key_locations[], data_ptr_t validitymask_locations[]);

	//===--------------------------------------------------------------------===//
	// Sorting Operators
	//===--------------------------------------------------------------------===//
	//! Scatter vector data to the rows in radix-sortable format.
	static void RadixScatter(Vector &v, idx_t vcount, const SelectionVector &sel, idx_t ser_count,
	                         data_ptr_t key_locations[], bool desc, bool has_null, bool nulls_first, idx_t prefix_len,
	                         idx_t width, idx_t offset = 0);

	//===--------------------------------------------------------------------===//
	// Out-of-Core Operators
	//===--------------------------------------------------------------------===//
	//! Swizzles blob pointers to offset within heap row
	static void SwizzleColumns(const RowLayout &layout, const data_ptr_t base_row_ptr, const idx_t count);
	//! Swizzles the base pointer of each row to offset within heap block
	static void SwizzleHeapPointer(const RowLayout &layout, data_ptr_t row_ptr, const data_ptr_t heap_base_ptr,
	                               const idx_t count);
	//! Unswizzles all offsets back to pointers
	static void UnswizzlePointers(const RowLayout &layout, const data_ptr_t base_row_ptr,
	                              const data_ptr_t base_heap_ptr, const idx_t count);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/row_layout.hpp
//
//
//===----------------------------------------------------------------------===//






//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/aggregate/aggregate_object.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class BoundAggregateExpression;

struct AggregateObject {
	AggregateObject(AggregateFunction function, FunctionData *bind_data, idx_t child_count, idx_t payload_size,
	                bool distinct, PhysicalType return_type, Expression *filter = nullptr);
	AggregateObject(BoundAggregateExpression *aggr);

	AggregateFunction function;
	FunctionData *bind_data;
	idx_t child_count;
	idx_t payload_size;
	bool distinct;
	PhysicalType return_type;
	Expression *filter = nullptr;

	static vector<AggregateObject> CreateAggregateObjects(const vector<BoundAggregateExpression *> &bindings);
};

struct AggregateFilterData {
	AggregateFilterData(Allocator &allocator, Expression &filter_expr, const vector<LogicalType> &payload_types);

	idx_t ApplyFilter(DataChunk &payload);

	ExpressionExecutor filter_executor;
	DataChunk filtered_payload;
	SelectionVector true_sel;
};

struct AggregateFilterDataSet {
	AggregateFilterDataSet();

	vector<unique_ptr<AggregateFilterData>> filter_data;

public:
	void Initialize(Allocator &allocator, const vector<AggregateObject> &aggregates,
	                const vector<LogicalType> &payload_types);

	AggregateFilterData &GetFilterData(idx_t aggr_idx);
};

} // namespace duckdb


namespace duckdb {

class RowLayout {
public:
	using Aggregates = vector<AggregateObject>;
	using ValidityBytes = TemplatedValidityMask<uint8_t>;

	//! Creates an empty RowLayout
	RowLayout();

public:
	//! Initializes the RowLayout with the specified types and aggregates to an empty RowLayout
	void Initialize(vector<LogicalType> types_p, Aggregates aggregates_p, bool align = true);
	//! Initializes the RowLayout with the specified types to an empty RowLayout
	void Initialize(vector<LogicalType> types, bool align = true);
	//! Initializes the RowLayout with the specified aggregates to an empty RowLayout
	void Initialize(Aggregates aggregates_p, bool align = true);
	//! Returns the number of data columns
	inline idx_t ColumnCount() const {
		return types.size();
	}
	//! Returns a list of the column types for this data chunk
	inline const vector<LogicalType> &GetTypes() const {
		return types;
	}
	//! Returns the number of aggregates
	inline idx_t AggregateCount() const {
		return aggregates.size();
	}
	//! Returns a list of the aggregates for this data chunk
	inline Aggregates &GetAggregates() {
		return aggregates;
	}
	//! Returns the total width required for each row, including padding
	inline idx_t GetRowWidth() const {
		return row_width;
	}
	//! Returns the offset to the start of the data
	inline idx_t GetDataOffset() const {
		return flag_width;
	}
	//! Returns the total width required for the data, including padding
	inline idx_t GetDataWidth() const {
		return data_width;
	}
	//! Returns the offset to the start of the aggregates
	inline idx_t GetAggrOffset() const {
		return flag_width + data_width;
	}
	//! Returns the total width required for the aggregates, including padding
	inline idx_t GetAggrWidth() const {
		return aggr_width;
	}
	//! Returns the column offsets into each row
	inline const vector<idx_t> &GetOffsets() const {
		return offsets;
	}
	//! Returns whether all columns in this layout are constant size
	inline bool AllConstant() const {
		return all_constant;
	}
	inline idx_t GetHeapPointerOffset() const {
		return heap_pointer_offset;
	}

private:
	//! The types of the data columns
	vector<LogicalType> types;
	//! The aggregate functions
	Aggregates aggregates;
	//! The width of the validity header
	idx_t flag_width;
	//! The width of the data portion
	idx_t data_width;
	//! The width of the aggregate state portion
	idx_t aggr_width;
	//! The width of the entire row
	idx_t row_width;
	//! The offsets to the columns and aggregate data in each row
	vector<idx_t> offsets;
	//! Whether all columns in this layout are constant size
	bool all_constant;
	//! Offset to the pointer to the heap for each row
	idx_t heap_pointer_offset;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/constant_operators.hpp
//
//
//===----------------------------------------------------------------------===//



namespace duckdb {

struct PickLeft {
	template <class T>
	static inline T Operation(T left, T right) {
		return left;
	}
};

struct PickRight {
	template <class T>
	static inline T Operation(T left, T right) {
		return right;
	}
};

struct NOP {
	template <class T>
	static inline T Operation(T left) {
		return left;
	}
};

struct ConstantZero {
	template <class T>
	static inline T Operation(T left, T right) {
		return 0;
	}
};

struct ConstantOne {
	template <class T>
	static inline T Operation(T left, T right) {
		return 1;
	}
};

struct AddOne {
	template <class T>
	static inline T Operation(T left, T right) {
		return right + 1;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/row_data_collection.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct RowDataBlock {
	RowDataBlock(BufferManager &buffer_manager, idx_t capacity, idx_t entry_size)
	    : capacity(capacity), entry_size(entry_size), count(0), byte_offset(0) {
		block = buffer_manager.RegisterMemory(capacity * entry_size, false);
	}
	//! The buffer block handle
	shared_ptr<BlockHandle> block;
	//! Capacity (number of entries) and entry size that fit in this block
	idx_t capacity;
	const idx_t entry_size;
	//! Number of entries currently in this block
	idx_t count;
	//! Write offset (if variable size entries)
	idx_t byte_offset;
};

struct BlockAppendEntry {
	BlockAppendEntry(data_ptr_t baseptr, idx_t count) : baseptr(baseptr), count(count) {
	}
	data_ptr_t baseptr;
	idx_t count;
};

class RowDataCollection {
public:
	RowDataCollection(BufferManager &buffer_manager, idx_t block_capacity, idx_t entry_size, bool keep_pinned = false);

	//! BufferManager
	BufferManager &buffer_manager;
	//! The total number of stored entries
	idx_t count;
	//! The number of entries per block
	idx_t block_capacity;
	//! Size of entries in the blocks
	idx_t entry_size;
	//! The blocks holding the main data
	vector<RowDataBlock> blocks;
	//! The blocks that this collection currently has pinned
	vector<BufferHandle> pinned_blocks;

public:
	idx_t AppendToBlock(RowDataBlock &block, BufferHandle &handle, vector<BlockAppendEntry> &append_entries,
	                    idx_t remaining, idx_t entry_sizes[]);
	vector<BufferHandle> Build(idx_t added_count, data_ptr_t key_locations[], idx_t entry_sizes[],
	                           const SelectionVector *sel = FlatVector::IncrementalSelectionVector());

	void Merge(RowDataCollection &other);

	//! The size (in bytes) of this RowDataCollection if it were stored in a single block
	idx_t SizeInBytes() const {
		idx_t bytes = 0;
		if (entry_size == 1) {
			for (auto &block : blocks) {
				bytes += block.byte_offset;
			}
		} else {
			bytes = count * entry_size;
		}
		return MaxValue(bytes, (idx_t)Storage::BLOCK_SIZE);
	}

private:
	mutex rdc_lock;

	//! Whether the blocks should stay pinned (necessary for e.g. a heap)
	const bool keep_pinned;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/serializer/buffered_deserializer.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class BufferedDeserializer : public Deserializer {
public:
	BufferedDeserializer(data_ptr_t ptr, idx_t data_size);
	explicit BufferedDeserializer(BufferedSerializer &serializer);

	data_ptr_t ptr;
	data_ptr_t endptr;

public:
	void ReadData(data_ptr_t buffer, uint64_t read_size) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/serializer/buffered_file_reader.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class BufferedFileReader : public Deserializer {
public:
	BufferedFileReader(FileSystem &fs, const char *path, FileOpener *opener = nullptr);

	FileSystem &fs;
	unique_ptr<data_t[]> data;
	idx_t offset;
	idx_t read_data;
	unique_ptr<FileHandle> handle;

public:
	void ReadData(data_ptr_t buffer, uint64_t read_size) override;
	//! Returns true if the reader has finished reading the entire file
	bool Finished();

	idx_t FileSize() {
		return file_size;
	}

private:
	idx_t file_size;
	idx_t total_read;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/sort/comparators.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct SortLayout;
struct SBScanState;

using ValidityBytes = RowLayout::ValidityBytes;

struct Comparators {
public:
	//! Whether a tie between two blobs can be broken
	static bool TieIsBreakable(const idx_t &col_idx, const data_ptr_t row_ptr, const RowLayout &row_layout);
	//! Compares the tuples that a being read from in the 'left' and 'right blocks during merge sort
	//! (only in case we cannot simply 'memcmp' - if there are blob columns)
	static int CompareTuple(const SBScanState &left, const SBScanState &right, const data_ptr_t &l_ptr,
	                        const data_ptr_t &r_ptr, const SortLayout &sort_layout, const bool &external_sort);
	//! Compare two blob values
	static int CompareVal(const data_ptr_t l_ptr, const data_ptr_t r_ptr, const LogicalType &type);

private:
	//! Compares two blob values that were initially tied by their prefix
	static int BreakBlobTie(const idx_t &tie_col, const SBScanState &left, const SBScanState &right,
	                        const SortLayout &sort_layout, const bool &external);
	//! Compare two fixed-size values
	template <class T>
	static int TemplatedCompareVal(const data_ptr_t &left_ptr, const data_ptr_t &right_ptr);

	//! Compare two values at the pointers (can be recursive if nested type)
	static int CompareValAndAdvance(data_ptr_t &l_ptr, data_ptr_t &r_ptr, const LogicalType &type);
	//! Compares two fixed-size values at the given pointers
	template <class T>
	static int TemplatedCompareAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr);
	//! Compares two string values at the given pointers
	static int CompareStringAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr);
	//! Compares two struct values at the given pointers (recursive)
	static int CompareStructAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr,
	                                   const child_list_t<LogicalType> &types);
	//! Compare two list values at the pointers (can be recursive if nested type)
	static int CompareListAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr, const LogicalType &type);
	//! Compares a list of fixed-size values
	template <class T>
	static int TemplatedCompareListLoop(data_ptr_t &left_ptr, data_ptr_t &right_ptr, const ValidityBytes &left_validity,
	                                    const ValidityBytes &right_validity, const idx_t &count);

	//! Unwizzles an offset into a pointer
	static void UnswizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type);
	//! Swizzles a pointer into an offset
	static void SwizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type);
};

} // namespace duckdb
//                         DuckDB
//
// duckdb/common/fast_mem.hpp
//
//
//===----------------------------------------------------------------------===//






template <size_t SIZE>
static inline void MemcpyFixed(void *dest, const void *src) {
	memcpy(dest, src, SIZE);
}

template <size_t SIZE>
static inline int MemcmpFixed(const void *str1, const void *str2) {
	return memcmp(str1, str2, SIZE);
}

namespace duckdb {

//! This templated memcpy is significantly faster than std::memcpy,
//! but only when you are calling memcpy with a const size in a loop.
//! For instance `while (<cond>) { memcpy(<dest>, <src>, const_size); ... }`
static inline void FastMemcpy(void *dest, const void *src, const size_t size) {
	// LCOV_EXCL_START
	switch (size) {
	case 0:
		return;
	case 1:
		return MemcpyFixed<1>(dest, src);
	case 2:
		return MemcpyFixed<2>(dest, src);
	case 3:
		return MemcpyFixed<3>(dest, src);
	case 4:
		return MemcpyFixed<4>(dest, src);
	case 5:
		return MemcpyFixed<5>(dest, src);
	case 6:
		return MemcpyFixed<6>(dest, src);
	case 7:
		return MemcpyFixed<7>(dest, src);
	case 8:
		return MemcpyFixed<8>(dest, src);
	case 9:
		return MemcpyFixed<9>(dest, src);
	case 10:
		return MemcpyFixed<10>(dest, src);
	case 11:
		return MemcpyFixed<11>(dest, src);
	case 12:
		return MemcpyFixed<12>(dest, src);
	case 13:
		return MemcpyFixed<13>(dest, src);
	case 14:
		return MemcpyFixed<14>(dest, src);
	case 15:
		return MemcpyFixed<15>(dest, src);
	case 16:
		return MemcpyFixed<16>(dest, src);
	case 17:
		return MemcpyFixed<17>(dest, src);
	case 18:
		return MemcpyFixed<18>(dest, src);
	case 19:
		return MemcpyFixed<19>(dest, src);
	case 20:
		return MemcpyFixed<20>(dest, src);
	case 21:
		return MemcpyFixed<21>(dest, src);
	case 22:
		return MemcpyFixed<22>(dest, src);
	case 23:
		return MemcpyFixed<23>(dest, src);
	case 24:
		return MemcpyFixed<24>(dest, src);
	case 25:
		return MemcpyFixed<25>(dest, src);
	case 26:
		return MemcpyFixed<26>(dest, src);
	case 27:
		return MemcpyFixed<27>(dest, src);
	case 28:
		return MemcpyFixed<28>(dest, src);
	case 29:
		return MemcpyFixed<29>(dest, src);
	case 30:
		return MemcpyFixed<30>(dest, src);
	case 31:
		return MemcpyFixed<31>(dest, src);
	case 32:
		return MemcpyFixed<32>(dest, src);
	case 33:
		return MemcpyFixed<33>(dest, src);
	case 34:
		return MemcpyFixed<34>(dest, src);
	case 35:
		return MemcpyFixed<35>(dest, src);
	case 36:
		return MemcpyFixed<36>(dest, src);
	case 37:
		return MemcpyFixed<37>(dest, src);
	case 38:
		return MemcpyFixed<38>(dest, src);
	case 39:
		return MemcpyFixed<39>(dest, src);
	case 40:
		return MemcpyFixed<40>(dest, src);
	case 41:
		return MemcpyFixed<41>(dest, src);
	case 42:
		return MemcpyFixed<42>(dest, src);
	case 43:
		return MemcpyFixed<43>(dest, src);
	case 44:
		return MemcpyFixed<44>(dest, src);
	case 45:
		return MemcpyFixed<45>(dest, src);
	case 46:
		return MemcpyFixed<46>(dest, src);
	case 47:
		return MemcpyFixed<47>(dest, src);
	case 48:
		return MemcpyFixed<48>(dest, src);
	case 49:
		return MemcpyFixed<49>(dest, src);
	case 50:
		return MemcpyFixed<50>(dest, src);
	case 51:
		return MemcpyFixed<51>(dest, src);
	case 52:
		return MemcpyFixed<52>(dest, src);
	case 53:
		return MemcpyFixed<53>(dest, src);
	case 54:
		return MemcpyFixed<54>(dest, src);
	case 55:
		return MemcpyFixed<55>(dest, src);
	case 56:
		return MemcpyFixed<56>(dest, src);
	case 57:
		return MemcpyFixed<57>(dest, src);
	case 58:
		return MemcpyFixed<58>(dest, src);
	case 59:
		return MemcpyFixed<59>(dest, src);
	case 60:
		return MemcpyFixed<60>(dest, src);
	case 61:
		return MemcpyFixed<61>(dest, src);
	case 62:
		return MemcpyFixed<62>(dest, src);
	case 63:
		return MemcpyFixed<63>(dest, src);
	case 64:
		return MemcpyFixed<64>(dest, src);
	case 65:
		return MemcpyFixed<65>(dest, src);
	case 66:
		return MemcpyFixed<66>(dest, src);
	case 67:
		return MemcpyFixed<67>(dest, src);
	case 68:
		return MemcpyFixed<68>(dest, src);
	case 69:
		return MemcpyFixed<69>(dest, src);
	case 70:
		return MemcpyFixed<70>(dest, src);
	case 71:
		return MemcpyFixed<71>(dest, src);
	case 72:
		return MemcpyFixed<72>(dest, src);
	case 73:
		return MemcpyFixed<73>(dest, src);
	case 74:
		return MemcpyFixed<74>(dest, src);
	case 75:
		return MemcpyFixed<75>(dest, src);
	case 76:
		return MemcpyFixed<76>(dest, src);
	case 77:
		return MemcpyFixed<77>(dest, src);
	case 78:
		return MemcpyFixed<78>(dest, src);
	case 79:
		return MemcpyFixed<79>(dest, src);
	case 80:
		return MemcpyFixed<80>(dest, src);
	case 81:
		return MemcpyFixed<81>(dest, src);
	case 82:
		return MemcpyFixed<82>(dest, src);
	case 83:
		return MemcpyFixed<83>(dest, src);
	case 84:
		return MemcpyFixed<84>(dest, src);
	case 85:
		return MemcpyFixed<85>(dest, src);
	case 86:
		return MemcpyFixed<86>(dest, src);
	case 87:
		return MemcpyFixed<87>(dest, src);
	case 88:
		return MemcpyFixed<88>(dest, src);
	case 89:
		return MemcpyFixed<89>(dest, src);
	case 90:
		return MemcpyFixed<90>(dest, src);
	case 91:
		return MemcpyFixed<91>(dest, src);
	case 92:
		return MemcpyFixed<92>(dest, src);
	case 93:
		return MemcpyFixed<93>(dest, src);
	case 94:
		return MemcpyFixed<94>(dest, src);
	case 95:
		return MemcpyFixed<95>(dest, src);
	case 96:
		return MemcpyFixed<96>(dest, src);
	case 97:
		return MemcpyFixed<97>(dest, src);
	case 98:
		return MemcpyFixed<98>(dest, src);
	case 99:
		return MemcpyFixed<99>(dest, src);
	case 100:
		return MemcpyFixed<100>(dest, src);
	case 101:
		return MemcpyFixed<101>(dest, src);
	case 102:
		return MemcpyFixed<102>(dest, src);
	case 103:
		return MemcpyFixed<103>(dest, src);
	case 104:
		return MemcpyFixed<104>(dest, src);
	case 105:
		return MemcpyFixed<105>(dest, src);
	case 106:
		return MemcpyFixed<106>(dest, src);
	case 107:
		return MemcpyFixed<107>(dest, src);
	case 108:
		return MemcpyFixed<108>(dest, src);
	case 109:
		return MemcpyFixed<109>(dest, src);
	case 110:
		return MemcpyFixed<110>(dest, src);
	case 111:
		return MemcpyFixed<111>(dest, src);
	case 112:
		return MemcpyFixed<112>(dest, src);
	case 113:
		return MemcpyFixed<113>(dest, src);
	case 114:
		return MemcpyFixed<114>(dest, src);
	case 115:
		return MemcpyFixed<115>(dest, src);
	case 116:
		return MemcpyFixed<116>(dest, src);
	case 117:
		return MemcpyFixed<117>(dest, src);
	case 118:
		return MemcpyFixed<118>(dest, src);
	case 119:
		return MemcpyFixed<119>(dest, src);
	case 120:
		return MemcpyFixed<120>(dest, src);
	case 121:
		return MemcpyFixed<121>(dest, src);
	case 122:
		return MemcpyFixed<122>(dest, src);
	case 123:
		return MemcpyFixed<123>(dest, src);
	case 124:
		return MemcpyFixed<124>(dest, src);
	case 125:
		return MemcpyFixed<125>(dest, src);
	case 126:
		return MemcpyFixed<126>(dest, src);
	case 127:
		return MemcpyFixed<127>(dest, src);
	case 128:
		return MemcpyFixed<128>(dest, src);
	case 129:
		return MemcpyFixed<129>(dest, src);
	case 130:
		return MemcpyFixed<130>(dest, src);
	case 131:
		return MemcpyFixed<131>(dest, src);
	case 132:
		return MemcpyFixed<132>(dest, src);
	case 133:
		return MemcpyFixed<133>(dest, src);
	case 134:
		return MemcpyFixed<134>(dest, src);
	case 135:
		return MemcpyFixed<135>(dest, src);
	case 136:
		return MemcpyFixed<136>(dest, src);
	case 137:
		return MemcpyFixed<137>(dest, src);
	case 138:
		return MemcpyFixed<138>(dest, src);
	case 139:
		return MemcpyFixed<139>(dest, src);
	case 140:
		return MemcpyFixed<140>(dest, src);
	case 141:
		return MemcpyFixed<141>(dest, src);
	case 142:
		return MemcpyFixed<142>(dest, src);
	case 143:
		return MemcpyFixed<143>(dest, src);
	case 144:
		return MemcpyFixed<144>(dest, src);
	case 145:
		return MemcpyFixed<145>(dest, src);
	case 146:
		return MemcpyFixed<146>(dest, src);
	case 147:
		return MemcpyFixed<147>(dest, src);
	case 148:
		return MemcpyFixed<148>(dest, src);
	case 149:
		return MemcpyFixed<149>(dest, src);
	case 150:
		return MemcpyFixed<150>(dest, src);
	case 151:
		return MemcpyFixed<151>(dest, src);
	case 152:
		return MemcpyFixed<152>(dest, src);
	case 153:
		return MemcpyFixed<153>(dest, src);
	case 154:
		return MemcpyFixed<154>(dest, src);
	case 155:
		return MemcpyFixed<155>(dest, src);
	case 156:
		return MemcpyFixed<156>(dest, src);
	case 157:
		return MemcpyFixed<157>(dest, src);
	case 158:
		return MemcpyFixed<158>(dest, src);
	case 159:
		return MemcpyFixed<159>(dest, src);
	case 160:
		return MemcpyFixed<160>(dest, src);
	case 161:
		return MemcpyFixed<161>(dest, src);
	case 162:
		return MemcpyFixed<162>(dest, src);
	case 163:
		return MemcpyFixed<163>(dest, src);
	case 164:
		return MemcpyFixed<164>(dest, src);
	case 165:
		return MemcpyFixed<165>(dest, src);
	case 166:
		return MemcpyFixed<166>(dest, src);
	case 167:
		return MemcpyFixed<167>(dest, src);
	case 168:
		return MemcpyFixed<168>(dest, src);
	case 169:
		return MemcpyFixed<169>(dest, src);
	case 170:
		return MemcpyFixed<170>(dest, src);
	case 171:
		return MemcpyFixed<171>(dest, src);
	case 172:
		return MemcpyFixed<172>(dest, src);
	case 173:
		return MemcpyFixed<173>(dest, src);
	case 174:
		return MemcpyFixed<174>(dest, src);
	case 175:
		return MemcpyFixed<175>(dest, src);
	case 176:
		return MemcpyFixed<176>(dest, src);
	case 177:
		return MemcpyFixed<177>(dest, src);
	case 178:
		return MemcpyFixed<178>(dest, src);
	case 179:
		return MemcpyFixed<179>(dest, src);
	case 180:
		return MemcpyFixed<180>(dest, src);
	case 181:
		return MemcpyFixed<181>(dest, src);
	case 182:
		return MemcpyFixed<182>(dest, src);
	case 183:
		return MemcpyFixed<183>(dest, src);
	case 184:
		return MemcpyFixed<184>(dest, src);
	case 185:
		return MemcpyFixed<185>(dest, src);
	case 186:
		return MemcpyFixed<186>(dest, src);
	case 187:
		return MemcpyFixed<187>(dest, src);
	case 188:
		return MemcpyFixed<188>(dest, src);
	case 189:
		return MemcpyFixed<189>(dest, src);
	case 190:
		return MemcpyFixed<190>(dest, src);
	case 191:
		return MemcpyFixed<191>(dest, src);
	case 192:
		return MemcpyFixed<192>(dest, src);
	case 193:
		return MemcpyFixed<193>(dest, src);
	case 194:
		return MemcpyFixed<194>(dest, src);
	case 195:
		return MemcpyFixed<195>(dest, src);
	case 196:
		return MemcpyFixed<196>(dest, src);
	case 197:
		return MemcpyFixed<197>(dest, src);
	case 198:
		return MemcpyFixed<198>(dest, src);
	case 199:
		return MemcpyFixed<199>(dest, src);
	case 200:
		return MemcpyFixed<200>(dest, src);
	case 201:
		return MemcpyFixed<201>(dest, src);
	case 202:
		return MemcpyFixed<202>(dest, src);
	case 203:
		return MemcpyFixed<203>(dest, src);
	case 204:
		return MemcpyFixed<204>(dest, src);
	case 205:
		return MemcpyFixed<205>(dest, src);
	case 206:
		return MemcpyFixed<206>(dest, src);
	case 207:
		return MemcpyFixed<207>(dest, src);
	case 208:
		return MemcpyFixed<208>(dest, src);
	case 209:
		return MemcpyFixed<209>(dest, src);
	case 210:
		return MemcpyFixed<210>(dest, src);
	case 211:
		return MemcpyFixed<211>(dest, src);
	case 212:
		return MemcpyFixed<212>(dest, src);
	case 213:
		return MemcpyFixed<213>(dest, src);
	case 214:
		return MemcpyFixed<214>(dest, src);
	case 215:
		return MemcpyFixed<215>(dest, src);
	case 216:
		return MemcpyFixed<216>(dest, src);
	case 217:
		return MemcpyFixed<217>(dest, src);
	case 218:
		return MemcpyFixed<218>(dest, src);
	case 219:
		return MemcpyFixed<219>(dest, src);
	case 220:
		return MemcpyFixed<220>(dest, src);
	case 221:
		return MemcpyFixed<221>(dest, src);
	case 222:
		return MemcpyFixed<222>(dest, src);
	case 223:
		return MemcpyFixed<223>(dest, src);
	case 224:
		return MemcpyFixed<224>(dest, src);
	case 225:
		return MemcpyFixed<225>(dest, src);
	case 226:
		return MemcpyFixed<226>(dest, src);
	case 227:
		return MemcpyFixed<227>(dest, src);
	case 228:
		return MemcpyFixed<228>(dest, src);
	case 229:
		return MemcpyFixed<229>(dest, src);
	case 230:
		return MemcpyFixed<230>(dest, src);
	case 231:
		return MemcpyFixed<231>(dest, src);
	case 232:
		return MemcpyFixed<232>(dest, src);
	case 233:
		return MemcpyFixed<233>(dest, src);
	case 234:
		return MemcpyFixed<234>(dest, src);
	case 235:
		return MemcpyFixed<235>(dest, src);
	case 236:
		return MemcpyFixed<236>(dest, src);
	case 237:
		return MemcpyFixed<237>(dest, src);
	case 238:
		return MemcpyFixed<238>(dest, src);
	case 239:
		return MemcpyFixed<239>(dest, src);
	case 240:
		return MemcpyFixed<240>(dest, src);
	case 241:
		return MemcpyFixed<241>(dest, src);
	case 242:
		return MemcpyFixed<242>(dest, src);
	case 243:
		return MemcpyFixed<243>(dest, src);
	case 244:
		return MemcpyFixed<244>(dest, src);
	case 245:
		return MemcpyFixed<245>(dest, src);
	case 246:
		return MemcpyFixed<246>(dest, src);
	case 247:
		return MemcpyFixed<247>(dest, src);
	case 248:
		return MemcpyFixed<248>(dest, src);
	case 249:
		return MemcpyFixed<249>(dest, src);
	case 250:
		return MemcpyFixed<250>(dest, src);
	case 251:
		return MemcpyFixed<251>(dest, src);
	case 252:
		return MemcpyFixed<252>(dest, src);
	case 253:
		return MemcpyFixed<253>(dest, src);
	case 254:
		return MemcpyFixed<254>(dest, src);
	case 255:
		return MemcpyFixed<255>(dest, src);
	case 256:
		return MemcpyFixed<256>(dest, src);
	default:
		memcpy(dest, src, size);
	}
	// LCOV_EXCL_STOP
}

//! This templated memcmp is significantly faster than std::memcmp,
//! but only when you are calling memcmp with a const size in a loop.
//! For instance `while (<cond>) { memcmp(<str1>, <str2>, const_size); ... }`
static inline int FastMemcmp(const void *str1, const void *str2, const size_t size) {
	// LCOV_EXCL_START
	switch (size) {
	case 0:
		return 0;
	case 1:
		return MemcmpFixed<1>(str1, str2);
	case 2:
		return MemcmpFixed<2>(str1, str2);
	case 3:
		return MemcmpFixed<3>(str1, str2);
	case 4:
		return MemcmpFixed<4>(str1, str2);
	case 5:
		return MemcmpFixed<5>(str1, str2);
	case 6:
		return MemcmpFixed<6>(str1, str2);
	case 7:
		return MemcmpFixed<7>(str1, str2);
	case 8:
		return MemcmpFixed<8>(str1, str2);
	case 9:
		return MemcmpFixed<9>(str1, str2);
	case 10:
		return MemcmpFixed<10>(str1, str2);
	case 11:
		return MemcmpFixed<11>(str1, str2);
	case 12:
		return MemcmpFixed<12>(str1, str2);
	case 13:
		return MemcmpFixed<13>(str1, str2);
	case 14:
		return MemcmpFixed<14>(str1, str2);
	case 15:
		return MemcmpFixed<15>(str1, str2);
	case 16:
		return MemcmpFixed<16>(str1, str2);
	case 17:
		return MemcmpFixed<17>(str1, str2);
	case 18:
		return MemcmpFixed<18>(str1, str2);
	case 19:
		return MemcmpFixed<19>(str1, str2);
	case 20:
		return MemcmpFixed<20>(str1, str2);
	case 21:
		return MemcmpFixed<21>(str1, str2);
	case 22:
		return MemcmpFixed<22>(str1, str2);
	case 23:
		return MemcmpFixed<23>(str1, str2);
	case 24:
		return MemcmpFixed<24>(str1, str2);
	case 25:
		return MemcmpFixed<25>(str1, str2);
	case 26:
		return MemcmpFixed<26>(str1, str2);
	case 27:
		return MemcmpFixed<27>(str1, str2);
	case 28:
		return MemcmpFixed<28>(str1, str2);
	case 29:
		return MemcmpFixed<29>(str1, str2);
	case 30:
		return MemcmpFixed<30>(str1, str2);
	case 31:
		return MemcmpFixed<31>(str1, str2);
	case 32:
		return MemcmpFixed<32>(str1, str2);
	case 33:
		return MemcmpFixed<33>(str1, str2);
	case 34:
		return MemcmpFixed<34>(str1, str2);
	case 35:
		return MemcmpFixed<35>(str1, str2);
	case 36:
		return MemcmpFixed<36>(str1, str2);
	case 37:
		return MemcmpFixed<37>(str1, str2);
	case 38:
		return MemcmpFixed<38>(str1, str2);
	case 39:
		return MemcmpFixed<39>(str1, str2);
	case 40:
		return MemcmpFixed<40>(str1, str2);
	case 41:
		return MemcmpFixed<41>(str1, str2);
	case 42:
		return MemcmpFixed<42>(str1, str2);
	case 43:
		return MemcmpFixed<43>(str1, str2);
	case 44:
		return MemcmpFixed<44>(str1, str2);
	case 45:
		return MemcmpFixed<45>(str1, str2);
	case 46:
		return MemcmpFixed<46>(str1, str2);
	case 47:
		return MemcmpFixed<47>(str1, str2);
	case 48:
		return MemcmpFixed<48>(str1, str2);
	case 49:
		return MemcmpFixed<49>(str1, str2);
	case 50:
		return MemcmpFixed<50>(str1, str2);
	case 51:
		return MemcmpFixed<51>(str1, str2);
	case 52:
		return MemcmpFixed<52>(str1, str2);
	case 53:
		return MemcmpFixed<53>(str1, str2);
	case 54:
		return MemcmpFixed<54>(str1, str2);
	case 55:
		return MemcmpFixed<55>(str1, str2);
	case 56:
		return MemcmpFixed<56>(str1, str2);
	case 57:
		return MemcmpFixed<57>(str1, str2);
	case 58:
		return MemcmpFixed<58>(str1, str2);
	case 59:
		return MemcmpFixed<59>(str1, str2);
	case 60:
		return MemcmpFixed<60>(str1, str2);
	case 61:
		return MemcmpFixed<61>(str1, str2);
	case 62:
		return MemcmpFixed<62>(str1, str2);
	case 63:
		return MemcmpFixed<63>(str1, str2);
	case 64:
		return MemcmpFixed<64>(str1, str2);
	default:
		return memcmp(str1, str2, size);
	}
	// LCOV_EXCL_STOP
}

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/sort/sort.hpp
//
//
//===----------------------------------------------------------------------===//



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





namespace duckdb {

class BufferManager;
struct RowDataBlock;
struct SortLayout;
struct GlobalSortState;

enum class SortedDataType { BLOB, PAYLOAD };

//! Object that holds sorted rows, and an accompanying heap if there are blobs
struct SortedData {
public:
	SortedData(SortedDataType type, const RowLayout &layout, BufferManager &buffer_manager, GlobalSortState &state);
	//! Number of rows that this object holds
	idx_t Count();
	//! Initialize new block to write to
	void CreateBlock();
	//! Create a slice that holds the rows between the start and end indices
	unique_ptr<SortedData> CreateSlice(idx_t start_block_index, idx_t end_block_index, idx_t end_entry_index);
	//! Unswizzles all
	void Unswizzle();

public:
	const SortedDataType type;
	//! Layout of this data
	const RowLayout layout;
	//! Data and heap blocks
	vector<RowDataBlock> data_blocks;
	vector<RowDataBlock> heap_blocks;
	//! Whether the pointers in this sorted data are swizzled
	bool swizzled;

private:
	//! The buffer manager
	BufferManager &buffer_manager;
	//! The global state
	GlobalSortState &state;
};

//! Block that holds sorted rows: radix, blob and payload data
struct SortedBlock {
public:
	SortedBlock(BufferManager &buffer_manager, GlobalSortState &gstate);
	//! Number of rows that this object holds
	idx_t Count() const;
	//! Initialize this block to write data to
	void InitializeWrite();
	//! Init new block to write to
	void CreateBlock();
	//! Fill this sorted block by appending the blocks held by a vector of sorted blocks
	void AppendSortedBlocks(vector<unique_ptr<SortedBlock>> &sorted_blocks);
	//! Locate the block and entry index of a row in this block,
	//! given an index between 0 and the total number of rows in this block
	void GlobalToLocalIndex(const idx_t &global_idx, idx_t &local_block_index, idx_t &local_entry_index);
	//! Create a slice that holds the rows between the start and end indices
	unique_ptr<SortedBlock> CreateSlice(const idx_t start, const idx_t end, idx_t &entry_idx);

	//! Size (in bytes) of the heap of this block
	idx_t HeapSize() const;
	//! Total size (in bytes) of this block
	idx_t SizeInBytes() const;

public:
	//! Radix/memcmp sortable data
	vector<RowDataBlock> radix_sorting_data;
	//! Variable sized sorting data
	unique_ptr<SortedData> blob_sorting_data;
	//! Payload data
	unique_ptr<SortedData> payload_data;

private:
	//! Buffer manager, global state, and sorting layout constants
	BufferManager &buffer_manager;
	GlobalSortState &state;
	const SortLayout &sort_layout;
	const RowLayout &payload_layout;
};

//! State used to scan a SortedBlock e.g. during merge sort
struct SBScanState {
public:
	SBScanState(BufferManager &buffer_manager, GlobalSortState &state);

	void PinRadix(idx_t block_idx_to);
	void PinData(SortedData &sd);

	data_ptr_t RadixPtr() const;
	data_ptr_t DataPtr(SortedData &sd) const;
	data_ptr_t HeapPtr(SortedData &sd) const;
	data_ptr_t BaseHeapPtr(SortedData &sd) const;

	idx_t Remaining() const;

	void SetIndices(idx_t block_idx_to, idx_t entry_idx_to);

public:
	BufferManager &buffer_manager;
	const SortLayout &sort_layout;
	GlobalSortState &state;

	SortedBlock *sb;

	idx_t block_idx;
	idx_t entry_idx;

	BufferHandle radix_handle;

	BufferHandle blob_sorting_data_handle;
	BufferHandle blob_sorting_heap_handle;

	BufferHandle payload_data_handle;
	BufferHandle payload_heap_handle;
};

//! Used to scan the data into DataChunks after sorting
struct PayloadScanner {
public:
	PayloadScanner(SortedData &sorted_data, GlobalSortState &global_sort_state, bool flush = true);
	explicit PayloadScanner(GlobalSortState &global_sort_state, bool flush = true);

	//! Scan a single block
	PayloadScanner(GlobalSortState &global_sort_state, idx_t block_idx);

	//! The type layout of the payload
	inline const vector<LogicalType> &GetPayloadTypes() const {
		return sorted_data.layout.GetTypes();
	}

	//! The number of rows scanned so far
	inline idx_t Scanned() const {
		return total_scanned;
	}

	//! The number of remaining rows
	inline idx_t Remaining() const {
		return total_count - total_scanned;
	}

	//! Scans the next data chunk from the sorted data
	void Scan(DataChunk &chunk);

private:
	//! The sorted data being scanned
	SortedData &sorted_data;
	//! Read state
	SBScanState read_state;
	//! The total count of sorted_data
	const idx_t total_count;
	//! The global sort state
	GlobalSortState &global_sort_state;
	//! Addresses used to gather from the sorted data
	Vector addresses = Vector(LogicalType::POINTER);
	//! The number of rows scanned so far
	idx_t total_scanned;
	//! Whether to flush the blocks after scanning
	const bool flush;
};

} // namespace duckdb




namespace duckdb {

class RowLayout;
struct LocalSortState;

struct SortConstants {
	static constexpr idx_t VALUES_PER_RADIX = 256;
	static constexpr idx_t MSD_RADIX_LOCATIONS = VALUES_PER_RADIX + 1;
	static constexpr idx_t INSERTION_SORT_THRESHOLD = 24;
	static constexpr idx_t MSD_RADIX_SORT_SIZE_THRESHOLD = 4;
};

struct SortLayout {
public:
	explicit SortLayout(const vector<BoundOrderByNode> &orders);

public:
	idx_t column_count;
	vector<OrderType> order_types;
	vector<OrderByNullType> order_by_null_types;
	vector<LogicalType> logical_types;

	bool all_constant;
	vector<bool> constant_size;
	vector<idx_t> column_sizes;
	vector<idx_t> prefix_lengths;
	vector<BaseStatistics *> stats;
	vector<bool> has_null;

	idx_t comparison_size;
	idx_t entry_size;

	RowLayout blob_layout;
	unordered_map<idx_t, idx_t> sorting_to_blob_col;
};

struct GlobalSortState {
public:
	GlobalSortState(BufferManager &buffer_manager, const vector<BoundOrderByNode> &orders, RowLayout &payload_layout);

	//! Add local state sorted data to this global state
	void AddLocalState(LocalSortState &local_sort_state);
	//! Prepares the GlobalSortState for the merge sort phase (after completing radix sort phase)
	void PrepareMergePhase();
	//! Initializes the global sort state for another round of merging
	void InitializeMergeRound();
	//! Completes the cascaded merge sort round.
	//! Pass true if you wish to use the radix data for further comparisons.
	void CompleteMergeRound(bool keep_radix_data = false);
	//! Print the sorted data to the console.
	void Print();

public:
	//! The lock for updating the order global state
	mutex lock;
	//! The buffer manager
	BufferManager &buffer_manager;

	//! Sorting and payload layouts
	const SortLayout sort_layout;
	const RowLayout payload_layout;

	//! Sorted data
	vector<unique_ptr<SortedBlock>> sorted_blocks;
	vector<vector<unique_ptr<SortedBlock>>> sorted_blocks_temp;
	unique_ptr<SortedBlock> odd_one_out;

	//! Pinned heap data (if sorting in memory)
	vector<RowDataBlock> heap_blocks;
	vector<BufferHandle> pinned_blocks;

	//! Capacity (number of rows) used to initialize blocks
	idx_t block_capacity;
	//! Whether we are doing an external sort
	bool external;

	//! Progress in merge path stage
	idx_t pair_idx;
	idx_t num_pairs;
	idx_t l_start;
	idx_t r_start;
};

struct LocalSortState {
public:
	LocalSortState();

	//! Initialize the layouts and RowDataCollections
	void Initialize(GlobalSortState &global_sort_state, BufferManager &buffer_manager_p);
	//! Sink one DataChunk into the local sort state
	void SinkChunk(DataChunk &sort, DataChunk &payload);
	//! Size of accumulated data in bytes
	idx_t SizeInBytes() const;
	//! Sort the data accumulated so far
	void Sort(GlobalSortState &global_sort_state, bool reorder_heap);

private:
	//! Concatenate the blocks held by a RowDataCollection into a single block
	RowDataBlock ConcatenateBlocks(RowDataCollection &row_data);
	//! Sorts the data in the newly created SortedBlock
	void SortInMemory();
	//! Re-order the local state after sorting
	void ReOrder(GlobalSortState &gstate, bool reorder_heap);
	//! Re-order a SortedData object after sorting
	void ReOrder(SortedData &sd, data_ptr_t sorting_ptr, RowDataCollection &heap, GlobalSortState &gstate,
	             bool reorder_heap);

public:
	//! Whether this local state has been initialized
	bool initialized;
	//! The buffer manager
	BufferManager *buffer_manager;
	//! The sorting and payload layouts
	const SortLayout *sort_layout;
	const RowLayout *payload_layout;
	//! Radix/memcmp sortable data
	unique_ptr<RowDataCollection> radix_sorting_data;
	//! Variable sized sorting data and accompanying heap
	unique_ptr<RowDataCollection> blob_sorting_data;
	unique_ptr<RowDataCollection> blob_sorting_heap;
	//! Payload data and accompanying heap
	unique_ptr<RowDataCollection> payload_data;
	unique_ptr<RowDataCollection> payload_heap;
	//! Sorted data
	vector<unique_ptr<SortedBlock>> sorted_blocks;

private:
	//! Selection vector and addresses for scattering the data to rows
	const SelectionVector &sel_ptr = *FlatVector::IncrementalSelectionVector();
	Vector addresses = Vector(LogicalType::POINTER);
};

struct MergeSorter {
public:
	MergeSorter(GlobalSortState &state, BufferManager &buffer_manager);

	//! Finds and merges partitions until the current cascaded merge round is finished
	void PerformInMergeRound();

private:
	//! The global sorting state
	GlobalSortState &state;
	//! The sorting and payload layouts
	BufferManager &buffer_manager;
	const SortLayout &sort_layout;

	//! The left and right reader
	unique_ptr<SBScanState> left;
	unique_ptr<SBScanState> right;

	//! Input and output blocks
	unique_ptr<SortedBlock> left_input;
	unique_ptr<SortedBlock> right_input;
	SortedBlock *result;

private:
	//! Computes the left and right block that will be merged next (Merge Path partition)
	void GetNextPartition();
	//! Finds the boundary of the next partition using binary search
	void GetIntersection(const idx_t diagonal, idx_t &l_idx, idx_t &r_idx);
	//! Compare values within SortedBlocks using a global index
	int CompareUsingGlobalIndex(SBScanState &l, SBScanState &r, const idx_t l_idx, const idx_t r_idx);

	//! Finds the next partition and merges it
	void MergePartition();

	//! Computes how the next 'count' tuples should be merged by setting the 'left_smaller' array
	void ComputeMerge(const idx_t &count, bool left_smaller[]);

	//! Merges the radix sorting blocks according to the 'left_smaller' array
	void MergeRadix(const idx_t &count, const bool left_smaller[]);
	//! Merges SortedData according to the 'left_smaller' array
	void MergeData(SortedData &result_data, SortedData &l_data, SortedData &r_data, const idx_t &count,
	               const bool left_smaller[], idx_t next_entry_sizes[], bool reset_indices);
	//! Merges constant size rows according to the 'left_smaller' array
	void MergeRows(data_ptr_t &l_ptr, idx_t &l_entry_idx, const idx_t &l_count, data_ptr_t &r_ptr, idx_t &r_entry_idx,
	               const idx_t &r_count, RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size,
	               const bool left_smaller[], idx_t &copied, const idx_t &count);
	//! Flushes constant size rows into the result
	void FlushRows(data_ptr_t &source_ptr, idx_t &source_entry_idx, const idx_t &source_count,
	               RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size, idx_t &copied,
	               const idx_t &count);
	//! Flushes blob rows and accompanying heap
	void FlushBlobs(const RowLayout &layout, const idx_t &source_count, data_ptr_t &source_data_ptr,
	                idx_t &source_entry_idx, data_ptr_t &source_heap_ptr, RowDataBlock *target_data_block,
	                data_ptr_t &target_data_ptr, RowDataBlock *target_heap_block, BufferHandle &target_heap_handle,
	                data_ptr_t &target_heap_ptr, idx_t &copied, const idx_t &count);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/tree_renderer.hpp
//
//
//===----------------------------------------------------------------------===//





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












#include <stack>



namespace duckdb {
class ClientContext;
class ExpressionExecutor;
class PhysicalOperator;
class SQLStatement;

//! The ExpressionInfo keeps information related to an expression
struct ExpressionInfo {
	explicit ExpressionInfo() : hasfunction(false) {
	}
	// A vector of children
	vector<unique_ptr<ExpressionInfo>> children;
	// Extract ExpressionInformation from a given expression state
	void ExtractExpressionsRecursive(unique_ptr<ExpressionState> &state);

	//! Whether or not expression has function
	bool hasfunction;
	//! The function Name
	string function_name;
	//! The function time
	uint64_t function_time = 0;
	//! Count the number of ALL tuples
	uint64_t tuples_count = 0;
	//! Count the number of tuples sampled
	uint64_t sample_tuples_count = 0;
};

//! The ExpressionRootInfo keeps information related to the root of an expression tree
struct ExpressionRootInfo {
	ExpressionRootInfo(ExpressionExecutorState &executor, string name);

	//! Count the number of time the executor called
	uint64_t total_count = 0;
	//! Count the number of time the executor called since last sampling
	uint64_t current_count = 0;
	//! Count the number of samples
	uint64_t sample_count = 0;
	//! Count the number of tuples in all samples
	uint64_t sample_tuples_count = 0;
	//! Count the number of tuples processed by this executor
	uint64_t tuples_count = 0;
	//! A vector which contain the pointer to root of each expression tree
	unique_ptr<ExpressionInfo> root;
	//! Name
	string name;
	//! Elapsed time
	double time;
	//! Extra Info
	string extra_info;
};

struct ExpressionExecutorInfo {
	explicit ExpressionExecutorInfo() {};
	explicit ExpressionExecutorInfo(ExpressionExecutor &executor, const string &name, int id);

	//! A vector which contain the pointer to all ExpressionRootInfo
	vector<unique_ptr<ExpressionRootInfo>> roots;
	//! Id, it will be used as index for executors_info vector
	int id;
};

struct OperatorInformation {
	explicit OperatorInformation(double time_ = 0, idx_t elements_ = 0) : time(time_), elements(elements_) {
	}

	double time = 0;
	idx_t elements = 0;
	string name;
	//! A vector of Expression Executor Info
	vector<unique_ptr<ExpressionExecutorInfo>> executors_info;
};

//! The OperatorProfiler measures timings of individual operators
class OperatorProfiler {
	friend class QueryProfiler;

public:
	DUCKDB_API explicit OperatorProfiler(bool enabled);

	DUCKDB_API void StartOperator(const PhysicalOperator *phys_op);
	DUCKDB_API void EndOperator(DataChunk *chunk);
	DUCKDB_API void Flush(const PhysicalOperator *phys_op, ExpressionExecutor *expression_executor, const string &name,
	                      int id);

	~OperatorProfiler() {
	}

private:
	void AddTiming(const PhysicalOperator *op, double time, idx_t elements);

	//! Whether or not the profiler is enabled
	bool enabled;
	//! The timer used to time the execution time of the individual Physical Operators
	Profiler op;
	//! The stack of Physical Operators that are currently active
	const PhysicalOperator *active_operator;
	//! A mapping of physical operators to recorded timings
	unordered_map<const PhysicalOperator *, OperatorInformation> timings;
};

//! The QueryProfiler can be used to measure timings of queries
class QueryProfiler {
public:
	DUCKDB_API QueryProfiler(ClientContext &context);

public:
	struct TreeNode {
		PhysicalOperatorType type;
		string name;
		string extra_info;
		OperatorInformation info;
		vector<unique_ptr<TreeNode>> children;
		idx_t depth = 0;
	};

	// Propagate save_location, enabled, detailed_enabled and automatic_print_format.
	void Propagate(QueryProfiler &qp);

	using TreeMap = unordered_map<const PhysicalOperator *, TreeNode *>;

private:
	unique_ptr<TreeNode> CreateTree(PhysicalOperator *root, idx_t depth = 0);
	void Render(const TreeNode &node, std::ostream &str) const;

public:
	DUCKDB_API bool IsEnabled() const;
	DUCKDB_API bool IsDetailedEnabled() const;
	DUCKDB_API ProfilerPrintFormat GetPrintFormat() const;
	DUCKDB_API string GetSaveLocation() const;

	DUCKDB_API static QueryProfiler &Get(ClientContext &context);

	DUCKDB_API void StartQuery(string query, bool is_explain_analyze = false);
	DUCKDB_API void EndQuery();

	DUCKDB_API void StartExplainAnalyze();

	//! Adds the timings gathered by an OperatorProfiler to this query profiler
	DUCKDB_API void Flush(OperatorProfiler &profiler);

	DUCKDB_API void StartPhase(string phase);
	DUCKDB_API void EndPhase();

	DUCKDB_API void Initialize(PhysicalOperator *root);

	DUCKDB_API string QueryTreeToString(bool print_optimizer_output = false) const;
	DUCKDB_API void QueryTreeToStream(std::ostream &str, bool print_optimizer_output = false) const;
	DUCKDB_API void Print();

	//! return the printed as a string. Unlike ToString, which is always formatted as a string,
	//! the return value is formatted based on the current print format (see GetPrintFormat()).
	DUCKDB_API string ToString() const;

	DUCKDB_API string ToJSON() const;
	DUCKDB_API void WriteToFile(const char *path, string &info) const;

	idx_t OperatorSize() {
		return tree_map.size();
	}

	void Finalize(TreeNode &node);

private:
	ClientContext &context;

	//! Whether or not the query profiler is running
	bool running;
	//! The lock used for flushing information from a thread into the global query profiler
	mutex flush_lock;

	//! Whether or not the query requires profiling
	bool query_requires_profiling;

	//! The root of the query tree
	unique_ptr<TreeNode> root;
	//! The query string
	string query;
	//! The timer used to time the execution time of the entire query
	Profiler main_query;
	//! A map of a Physical Operator pointer to a tree node
	TreeMap tree_map;
	//! Whether or not we are running as part of a explain_analyze query
	bool is_explain_analyze;

public:
	const TreeMap &GetTreeMap() const {
		return tree_map;
	}

private:
	//! The timer used to time the individual phases of the planning process
	Profiler phase_profiler;
	//! A mapping of the phase names to the timings
	using PhaseTimingStorage = unordered_map<string, double>;
	PhaseTimingStorage phase_timings;
	using PhaseTimingItem = PhaseTimingStorage::value_type;
	//! The stack of currently active phases
	vector<string> phase_stack;

private:
	vector<PhaseTimingItem> GetOrderedPhaseTimings() const;

	//! Check whether or not an operator type requires query profiling. If none of the ops in a query require profiling
	//! no profiling information is output.
	bool OperatorRequiresProfiling(PhysicalOperatorType op_type);
};

//! The QueryProfilerHistory can be used to access the profiler of previous queries
class QueryProfilerHistory {
private:
	//! Previous Query profilers
	deque<pair<transaction_t, shared_ptr<QueryProfiler>>> prev_profilers;
	//! Previous Query profilers size
	uint64_t prev_profilers_size = 20;

public:
	deque<pair<transaction_t, shared_ptr<QueryProfiler>>> &GetPrevProfilers() {
		return prev_profilers;
	}
	QueryProfilerHistory() {
	}

	void SetPrevProfilersSize(uint64_t prevProfilersSize) {
		prev_profilers_size = prevProfilersSize;
	}
	uint64_t GetPrevProfilersSize() const {
		return prev_profilers_size;
	}

public:
	void SetProfilerHistorySize(uint64_t size) {
		this->prev_profilers_size = size;
	}
};
} // namespace duckdb


namespace duckdb {
class LogicalOperator;
class PhysicalOperator;
class Pipeline;
struct PipelineRenderNode;

struct RenderTreeNode {
	string name;
	string extra_text;
};

struct RenderTree {
	RenderTree(idx_t width, idx_t height);

	unique_ptr<unique_ptr<RenderTreeNode>[]> nodes;
	idx_t width;
	idx_t height;

public:
	RenderTreeNode *GetNode(idx_t x, idx_t y);
	void SetNode(idx_t x, idx_t y, unique_ptr<RenderTreeNode> node);
	bool HasNode(idx_t x, idx_t y);

	idx_t GetPosition(idx_t x, idx_t y);
};

struct TreeRendererConfig {
	void enable_detailed() {
		MAX_EXTRA_LINES = 1000;
		detailed = true;
	}

	void enable_standard() {
		MAX_EXTRA_LINES = 30;
		detailed = false;
	}

	idx_t MAXIMUM_RENDER_WIDTH = 240;
	idx_t NODE_RENDER_WIDTH = 29;
	idx_t MINIMUM_RENDER_WIDTH = 15;
	idx_t MAX_EXTRA_LINES = 30;
	bool detailed = false;

#ifndef DUCKDB_ASCII_TREE_RENDERER
	const char *LTCORNER = "\342\224\214"; // "┌";
	const char *RTCORNER = "\342\224\220"; // "┐";
	const char *LDCORNER = "\342\224\224"; // "└";
	const char *RDCORNER = "\342\224\230"; // "┘";

	const char *MIDDLE = "\342\224\274";  // "┼";
	const char *TMIDDLE = "\342\224\254"; // "┬";
	const char *LMIDDLE = "\342\224\234"; // "├";
	const char *RMIDDLE = "\342\224\244"; // "┤";
	const char *DMIDDLE = "\342\224\264"; // "┴";

	const char *VERTICAL = "\342\224\202";   // "│";
	const char *HORIZONTAL = "\342\224\200"; // "─";
#else
	// ASCII version
	const char *LTCORNER = "<";
	const char *RTCORNER = ">";
	const char *LDCORNER = "<";
	const char *RDCORNER = ">";

	const char *MIDDLE = "+";
	const char *TMIDDLE = "+";
	const char *LMIDDLE = "+";
	const char *RMIDDLE = "+";
	const char *DMIDDLE = "+";

	const char *VERTICAL = "|";
	const char *HORIZONTAL = "-";
#endif
};

class TreeRenderer {
public:
	explicit TreeRenderer(TreeRendererConfig config_p = TreeRendererConfig()) : config(move(config_p)) {
	}

	string ToString(const LogicalOperator &op);
	string ToString(const PhysicalOperator &op);
	string ToString(const QueryProfiler::TreeNode &op);
	string ToString(const Pipeline &op);

	void Render(const LogicalOperator &op, std::ostream &ss);
	void Render(const PhysicalOperator &op, std::ostream &ss);
	void Render(const QueryProfiler::TreeNode &op, std::ostream &ss);
	void Render(const Pipeline &op, std::ostream &ss);

	void ToStream(RenderTree &root, std::ostream &ss);

	void EnableDetailed() {
		config.enable_detailed();
	}
	void EnableStandard() {
		config.enable_standard();
	}

private:
	unique_ptr<RenderTree> CreateTree(const LogicalOperator &op);
	unique_ptr<RenderTree> CreateTree(const PhysicalOperator &op);
	unique_ptr<RenderTree> CreateTree(const QueryProfiler::TreeNode &op);
	unique_ptr<RenderTree> CreateTree(const Pipeline &op);

	string ExtraInfoSeparator();
	unique_ptr<RenderTreeNode> CreateRenderNode(string name, string extra_info);
	unique_ptr<RenderTreeNode> CreateNode(const LogicalOperator &op);
	unique_ptr<RenderTreeNode> CreateNode(const PhysicalOperator &op);
	unique_ptr<RenderTreeNode> CreateNode(const QueryProfiler::TreeNode &op);
	unique_ptr<RenderTreeNode> CreateNode(const PipelineRenderNode &op);

private:
	//! The configuration used for rendering
	TreeRendererConfig config;

private:
	void RenderTopLayer(RenderTree &root, std::ostream &ss, idx_t y);
	void RenderBoxContent(RenderTree &root, std::ostream &ss, idx_t y);
	void RenderBottomLayer(RenderTree &root, std::ostream &ss, idx_t y);

	bool CanSplitOnThisChar(char l);
	bool IsPadding(char l);
	string RemovePadding(string l);
	void SplitUpExtraInfo(const string &extra_info, vector<string> &result);
	void SplitStringBuffer(const string &source, vector<string> &result);

	template <class T>
	idx_t CreateRenderTreeRecursive(RenderTree &result, const T &op, idx_t x, idx_t y);

	template <class T>
	unique_ptr<RenderTree> CreateRenderTree(const T &op);
	string ExtractExpressionsRecursive(ExpressionInfo &states);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_delim_join.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class PhysicalHashAggregate;

//! PhysicalDelimJoin represents a join where the LHS will be duplicate eliminated and pushed into a
//! PhysicalChunkCollectionScan in the RHS.
class PhysicalDelimJoin : public PhysicalOperator {
public:
	PhysicalDelimJoin(vector<LogicalType> types, unique_ptr<PhysicalOperator> original_join,
	                  vector<PhysicalOperator *> delim_scans, idx_t estimated_cardinality);

	unique_ptr<PhysicalOperator> join;
	unique_ptr<PhysicalHashAggregate> distinct;
	vector<PhysicalOperator *> delim_scans;

public:
	vector<PhysicalOperator *> GetChildren() const override;

public:
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

	string ParamsToString() const override;

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp
//
//
//===----------------------------------------------------------------------===//





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







namespace duckdb {

using GroupingSet = set<idx_t>;

class GroupByNode {
public:
	//! The total set of all group expressions
	vector<unique_ptr<ParsedExpression>> group_expressions;
	//! The different grouping sets as they map to the group expressions
	vector<GroupingSet> grouping_sets;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/radix_partitioned_hashtable.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/partitionable_hashtable.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/aggregate_hashtable.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/base_aggregate_hashtable.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
class BufferManager;

class BaseAggregateHashTable {
public:
	BaseAggregateHashTable(Allocator &allocator, const vector<AggregateObject> &aggregates,
	                       BufferManager &buffer_manager, vector<LogicalType> payload_types);
	virtual ~BaseAggregateHashTable() {
	}

protected:
	Allocator &allocator;
	BufferManager &buffer_manager;
	//! A helper for managing offsets into the data buffers
	RowLayout layout;
	//! The types of the payload columns stored in the hashtable
	vector<LogicalType> payload_types;
	//! Intermediate structures and data for aggregate filters
	AggregateFilterDataSet filter_set;
};

} // namespace duckdb



namespace duckdb {
class BlockHandle;
class BufferHandle;
class RowDataCollection;

struct FlushMoveState;

//! GroupedAggregateHashTable is a linear probing HT that is used for computing
//! aggregates
/*!
    GroupedAggregateHashTable is a HT that is used for computing aggregates. It takes
   as input the set of groups and the types of the aggregates to compute and
   stores them in the HT. It uses linear probing for collision resolution.
*/

// two part hash table
// hashes and payload
// hashes layout:
// [SALT][PAGE_NR][PAGE_OFFSET]
// [SALT] are the high bits of the hash value, e.g. 16 for 64 bit hashes
// [PAGE_NR] is the buffer managed payload page index
// [PAGE_OFFSET] is the logical entry offset into said payload page

// NOTE: PAGE_NR and PAGE_OFFSET are reversed for 64 bit HTs because struct packing

// payload layout
// [VALIDITY][GROUPS][HASH][PADDING][PAYLOAD]
// [VALIDITY] is the validity bits of the data columns (including the HASH)
// [GROUPS] is the group data, could be multiple values, fixed size, strings are elsewhere
// [HASH] is the hash data of the groups
// [PADDING] is gunk data to align payload properly
// [PAYLOAD] is the payload (i.e. the aggregate states)
struct aggr_ht_entry_64 {
	uint16_t salt;
	uint16_t page_offset;
	uint32_t page_nr; // this has to come last because alignment
};

struct aggr_ht_entry_32 {
	uint8_t salt;
	uint8_t page_nr;
	uint16_t page_offset;
};

enum HtEntryType { HT_WIDTH_32, HT_WIDTH_64 };

class GroupedAggregateHashTable : public BaseAggregateHashTable {
public:
	//! The hash table load factor, when a resize is triggered
	constexpr static float LOAD_FACTOR = 1.5;
	constexpr static uint8_t HASH_WIDTH = sizeof(hash_t);

public:
	GroupedAggregateHashTable(Allocator &allocator, BufferManager &buffer_manager, vector<LogicalType> group_types,
	                          vector<LogicalType> payload_types, const vector<BoundAggregateExpression *> &aggregates,
	                          HtEntryType entry_type = HtEntryType::HT_WIDTH_64);
	GroupedAggregateHashTable(Allocator &allocator, BufferManager &buffer_manager, vector<LogicalType> group_types,
	                          vector<LogicalType> payload_types, vector<AggregateObject> aggregates,
	                          HtEntryType entry_type = HtEntryType::HT_WIDTH_64);
	GroupedAggregateHashTable(Allocator &allocator, BufferManager &buffer_manager, vector<LogicalType> group_types);
	~GroupedAggregateHashTable() override;

	//! The stringheap of the AggregateHashTable
	unique_ptr<RowDataCollection> string_heap;

public:
	//! Add the given data to the HT, computing the aggregates grouped by the
	//! data in the group chunk. When resize = true, aggregates will not be
	//! computed but instead just assigned.
	idx_t AddChunk(DataChunk &groups, DataChunk &payload);
	idx_t AddChunk(DataChunk &groups, Vector &group_hashes, DataChunk &payload);

	//! Scan the HT starting from the scan_position until the result and group
	//! chunks are filled. scan_position will be updated by this function.
	//! Returns the amount of elements found.
	idx_t Scan(idx_t &scan_position, DataChunk &result);

	//! Fetch the aggregates for specific groups from the HT and place them in the result
	void FetchAggregates(DataChunk &groups, DataChunk &result);

	//! Finds or creates groups in the hashtable using the specified group keys. The addresses vector will be filled
	//! with pointers to the groups in the hash table, and the new_groups selection vector will point to the newly
	//! created groups. The return value is the amount of newly created groups.
	idx_t FindOrCreateGroups(DataChunk &groups, Vector &group_hashes, Vector &addresses_out,
	                         SelectionVector &new_groups_out);
	idx_t FindOrCreateGroups(DataChunk &groups, Vector &addresses_out, SelectionVector &new_groups_out);
	void FindOrCreateGroups(DataChunk &groups, Vector &addresses_out);

	//! Executes the filter(if any) and update the aggregates
	void Combine(GroupedAggregateHashTable &other);

	idx_t Size() {
		return entries;
	}

	idx_t MaxCapacity();

	void Partition(vector<GroupedAggregateHashTable *> &partition_hts, hash_t mask, idx_t shift);

	void Finalize();

private:
	HtEntryType entry_type;

	//! The total tuple size
	idx_t tuple_size;
	//! The amount of tuples that fit in a single block
	idx_t tuples_per_block;
	//! The capacity of the HT. This can be increased using
	//! GroupedAggregateHashTable::Resize
	idx_t capacity;
	//! The amount of entries stored in the HT currently
	idx_t entries;
	//! The data of the HT
	vector<BufferHandle> payload_hds;
	vector<data_ptr_t> payload_hds_ptrs;

	//! The hashes of the HT
	BufferHandle hashes_hdl;
	data_ptr_t hashes_hdl_ptr;
	data_ptr_t hashes_end_ptr; // of hashes
	idx_t hash_offset;         // Offset into the layout of the hash column

	hash_t hash_prefix_shift;
	idx_t payload_page_offset;

	//! Bitmask for getting relevant bits from the hashes to determine the position
	hash_t bitmask;

	vector<unique_ptr<GroupedAggregateHashTable>> distinct_hashes;

	bool is_finalized;

	// some stuff from FindOrCreateGroupsInternal() to avoid allocation there
	Vector ht_offsets;
	Vector hash_salts;
	SelectionVector group_compare_vector;
	SelectionVector no_match_vector;
	SelectionVector empty_vector;
	vector<ExpressionType> predicates;

private:
	GroupedAggregateHashTable(const GroupedAggregateHashTable &) = delete;

	//! Resize the HT to the specified size. Must be larger than the current
	//! size.
	void Destroy();

	void Verify();

	void FlushMove(FlushMoveState &state, Vector &source_addresses, Vector &source_hashes, idx_t count);
	void NewBlock();

	template <class ENTRY>
	void VerifyInternal();
	template <class ENTRY>
	void Resize(idx_t size);
	template <class ENTRY>
	idx_t FindOrCreateGroupsInternal(DataChunk &groups, Vector &group_hashes, Vector &addresses,
	                                 SelectionVector &new_groups);

	template <class FUNC = std::function<void(idx_t, idx_t, data_ptr_t)>>
	void PayloadApply(FUNC fun);
};

} // namespace duckdb


namespace duckdb {

struct RadixPartitionInfo {
	explicit RadixPartitionInfo(idx_t _n_partitions_upper_bound);
	const idx_t n_partitions;
	const idx_t radix_bits;
	const hash_t radix_mask;
	constexpr static idx_t RADIX_SHIFT = 40;
};

typedef vector<unique_ptr<GroupedAggregateHashTable>> HashTableList;

class PartitionableHashTable {
public:
	PartitionableHashTable(Allocator &allocator, BufferManager &buffer_manager_p, RadixPartitionInfo &partition_info_p,
	                       vector<LogicalType> group_types_p, vector<LogicalType> payload_types_p,
	                       vector<BoundAggregateExpression *> bindings_p);

	idx_t AddChunk(DataChunk &groups, DataChunk &payload, bool do_partition);
	void Partition();
	bool IsPartitioned();

	HashTableList GetPartition(idx_t partition);
	HashTableList GetUnpartitioned();

	void Finalize();

private:
	Allocator &allocator;
	BufferManager &buffer_manager;
	vector<LogicalType> group_types;
	vector<LogicalType> payload_types;
	vector<BoundAggregateExpression *> bindings;

	bool is_partitioned;
	RadixPartitionInfo &partition_info;
	vector<SelectionVector> sel_vectors;
	vector<idx_t> sel_vector_sizes;
	DataChunk group_subset, payload_subset;
	Vector hashes, hashes_subset;

	HashTableList unpartitioned_hts;
	unordered_map<hash_t, HashTableList> radix_partitioned_hts;

private:
	idx_t ListAddChunk(HashTableList &list, DataChunk &groups, Vector &group_hashes, DataChunk &payload);
};
} // namespace duckdb




namespace duckdb {
class BufferManager;
class Executor;
class PhysicalHashAggregate;
class Pipeline;
class Task;

class RadixPartitionedHashTable {
public:
	RadixPartitionedHashTable(GroupingSet &grouping_set, const PhysicalHashAggregate &op);

	GroupingSet &grouping_set;
	vector<idx_t> null_groups;
	const PhysicalHashAggregate &op;

	vector<LogicalType> group_types;
	//! how many groups can we have in the operator before we switch to radix partitioning
	idx_t radix_limit;

	//! The GROUPING values that belong to this hash table
	vector<Value> grouping_values;

public:
	//! Sink Interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const;

	void Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate, DataChunk &input,
	          DataChunk &aggregate_input_chunk) const;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const;
	bool Finalize(ClientContext &context, GlobalSinkState &gstate_p) const;

	void ScheduleTasks(Executor &executor, const shared_ptr<Event> &event, GlobalSinkState &state,
	                   vector<unique_ptr<Task>> &tasks) const;

	//! Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSinkState &sink_state,
	             GlobalSourceState &gstate_p) const;

	static void SetMultiScan(GlobalSinkState &state);
	bool ForceSingleHT(GlobalSinkState &state) const;
};

} // namespace duckdb


namespace duckdb {

class ClientContext;
class BufferManager;

//! PhysicalHashAggregate is an group-by and aggregate implementation that uses
//! a hash table to perform the grouping
class PhysicalHashAggregate : public PhysicalOperator {
public:
	PhysicalHashAggregate(ClientContext &context, vector<LogicalType> types, vector<unique_ptr<Expression>> expressions,
	                      idx_t estimated_cardinality, PhysicalOperatorType type = PhysicalOperatorType::HASH_GROUP_BY);
	PhysicalHashAggregate(ClientContext &context, vector<LogicalType> types, vector<unique_ptr<Expression>> expressions,
	                      vector<unique_ptr<Expression>> groups, idx_t estimated_cardinality,
	                      PhysicalOperatorType type = PhysicalOperatorType::HASH_GROUP_BY);
	PhysicalHashAggregate(ClientContext &context, vector<LogicalType> types, vector<unique_ptr<Expression>> expressions,
	                      vector<unique_ptr<Expression>> groups, vector<GroupingSet> grouping_sets,
	                      vector<vector<idx_t>> grouping_functions, idx_t estimated_cardinality,
	                      PhysicalOperatorType type = PhysicalOperatorType::HASH_GROUP_BY);

	//! The groups
	vector<unique_ptr<Expression>> groups;
	//! The grouping sets
	vector<GroupingSet> grouping_sets;
	//! The aggregates that have to be computed
	vector<unique_ptr<Expression>> aggregates;
	//! The set of GROUPING functions
	vector<vector<idx_t>> grouping_functions;

	//! Whether or not any aggregation is DISTINCT
	bool any_distinct;

	//! The group types
	vector<LogicalType> group_types;
	//! The payload types
	vector<LogicalType> payload_types;
	//! The aggregate return types
	vector<LogicalType> aggregate_return_types;

	//! The radix partitioned hash tables (one per grouping set)
	vector<RadixPartitionedHashTable> radix_tables;

	//! Pointers to the aggregates
	vector<BoundAggregateExpression *> bindings;

	unordered_map<Expression *, size_t> filter_indexes;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool IsSink() const override {
		return true;
	}

	bool ParallelSink() const override {
		return true;
	}

public:
	string ParamsToString() const override;
	//! Toggle multi-scan capability on a hash table, which prevents the scan of the aggregate from being destructive
	//! If this is not toggled the GetData method will destroy the hash table as it is scanning it
	static void SetMultiScan(GlobalSinkState &state);
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #2
// See the end of this file for a list



#include <string>
#include <cassert>
#include <cstring>

namespace duckdb {

enum class UnicodeType { INVALID, ASCII, UNICODE };
enum class UnicodeInvalidReason { BYTE_MISMATCH, NULL_BYTE };

class Utf8Proc {
public:
	//! Distinguishes ASCII, Valid UTF8 and Invalid UTF8 strings
	static UnicodeType Analyze(const char *s, size_t len, UnicodeInvalidReason *invalid_reason = nullptr, size_t *invalid_pos = nullptr);
	//! Performs UTF NFC normalization of string, return value needs to be free'd
	static char* Normalize(const char* s, size_t len);
	//! Returns whether or not the UTF8 string is valid
	static bool IsValid(const char *s, size_t len);
	//! Returns the position (in bytes) of the next grapheme cluster
	static size_t NextGraphemeCluster(const char *s, size_t len, size_t pos);
	//! Returns the position (in bytes) of the previous grapheme cluster
	static size_t PreviousGraphemeCluster(const char *s, size_t len, size_t pos);

	//! Transform a codepoint to utf8 and writes it to "c", sets "sz" to the size of the codepoint
	static bool CodepointToUtf8(int cp, int &sz, char *c);
	//! Returns the codepoint length in bytes when encoded in UTF8
	static int CodepointLength(int cp);
	//! Transform a UTF8 string to a codepoint; returns the codepoint and writes the length of the codepoint (in UTF8) to sz
	static int32_t UTF8ToCodepoint(const char *c, int &sz);
	static size_t RenderWidth(const char *s, size_t len, size_t pos);

};

}


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






namespace duckdb {

struct BatchedChunkScanState {
	map<idx_t, unique_ptr<ChunkCollection>>::iterator iterator;
	idx_t chunk_index;
};

//!  A BatchedChunkCollection holds a number of data entries that are partitioned by batch index
//! Scans over a BatchedChunkCollection are ordered by batch index
class BatchedChunkCollection {
public:
	DUCKDB_API BatchedChunkCollection(Allocator &allocator);

	//! Appends a datachunk with the given batch index to the batched collection
	DUCKDB_API void Append(DataChunk &input, idx_t batch_index);

	//! Merge the other batched chunk collection into this batched collection
	DUCKDB_API void Merge(BatchedChunkCollection &other);

	//! Initialize a scan over the batched chunk collection
	DUCKDB_API void InitializeScan(BatchedChunkScanState &state);

	//! Scan a chunk from the batched chunk collection, in-order of batch index
	DUCKDB_API void Scan(BatchedChunkScanState &state, DataChunk &output);

	DUCKDB_API string ToString() const;
	DUCKDB_API void Print() const;

private:
	Allocator &allocator;
	//! The data of the batched chunk collection - a set of batch_index -> ChunkCollection pointers
	map<idx_t, unique_ptr<ChunkCollection>> data;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/value_operations/value_operations.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct ValueOperations {
	//===--------------------------------------------------------------------===//
	// Comparison Operations
	//===--------------------------------------------------------------------===//
	// A == B
	static bool Equals(const Value &left, const Value &right);
	// A != B
	static bool NotEquals(const Value &left, const Value &right);
	// A > B
	static bool GreaterThan(const Value &left, const Value &right);
	// A >= B
	static bool GreaterThanEquals(const Value &left, const Value &right);
	// A < B
	static bool LessThan(const Value &left, const Value &right);
	// A <= B
	static bool LessThanEquals(const Value &left, const Value &right);
	//===--------------------------------------------------------------------===//
	// Distinction Operations
	//===--------------------------------------------------------------------===//
	// A == B, NULLs equal
	static bool NotDistinctFrom(const Value &left, const Value &right);
	// A != B, NULLs equal
	static bool DistinctFrom(const Value &left, const Value &right);
	// A > B, NULLs last
	static bool DistinctGreaterThan(const Value &left, const Value &right);
	// A >= B, NULLs last
	static bool DistinctGreaterThanEquals(const Value &left, const Value &right);
	// A < B, NULLs last
	static bool DistinctLessThan(const Value &left, const Value &right);
	// A <= B, NULLs last
	static bool DistinctLessThanEquals(const Value &left, const Value &right);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/array.hpp
//
//
//===----------------------------------------------------------------------===//



#include <array>

namespace duckdb {
using std::array;
}
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/sel_cache.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Selection vector cache used for caching vector slices
struct SelCache {
	unordered_map<sel_t *, buffer_ptr<VectorBuffer>> cache;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/arrow_aux_data.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct ArrowAuxiliaryData : VectorAuxiliaryData {
	explicit ArrowAuxiliaryData(shared_ptr<ArrowArrayWrapper> arrow_array_p)
	    : VectorAuxiliaryData(VectorAuxiliaryDataType::ARROW_AUXILIARY), arrow_array(std::move(arrow_array_p)) {
	}
	~ArrowAuxiliaryData() override {
	}

	shared_ptr<ArrowArrayWrapper> arrow_array;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/types/hyperloglog.hpp
//
//
//===----------------------------------------------------------------------===//







// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #7
// See the end of this file for a list

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// third_party/hyperloglog/hyperloglog.hpp
//
//
//===----------------------------------------------------------------------===//



#include <stdint.h>
#include <string.h>

namespace duckdb_hll {

/* Error codes */
#define HLL_C_OK  0
#define HLL_C_ERR -1

typedef struct {
	void *ptr;
} robj;

//! Create a new empty HyperLogLog object
robj *hll_create(void);
//! Convert hll from sparse to dense
int hllSparseToDense(robj *o);
//! Destroy the specified HyperLogLog object
void hll_destroy(robj *obj);
//! Add an element with the specified amount of bytes to the HyperLogLog. Returns C_ERR on failure, otherwise returns 0
//! if the cardinality did not change, and 1 otherwise.
int hll_add(robj *o, unsigned char *ele, size_t elesize);
//! Returns the estimated amount of unique elements seen by the HyperLogLog. Returns C_OK on success, or C_ERR on
//! failure.
int hll_count(robj *o, size_t *result);
//! Merge hll_count HyperLogLog objects into a single one. Returns NULL on failure, or the new HLL object on success.
robj *hll_merge(robj **hlls, size_t hll_count);
//! Get size (in bytes) of the HLL
uint64_t get_size();

uint64_t MurmurHash64A(const void *key, int len, unsigned int seed);

} // namespace duckdb_hll

namespace duckdb {

void AddToLogsInternal(VectorData &vdata, idx_t count, uint64_t indices[], uint8_t counts[], void ***logs[],
                       const SelectionVector *log_sel);

void AddToSingleLogInternal(VectorData &vdata, idx_t count, uint64_t indices[], uint8_t counts[], void *log);

} // namespace duckdb


// LICENSE_CHANGE_END


namespace duckdb {

enum class HLLStorageType { UNCOMPRESSED = 1 };

class FieldWriter;
class FieldReader;

//! The HyperLogLog class holds a HyperLogLog counter for approximate cardinality counting
class HyperLogLog {
public:
	HyperLogLog();
	~HyperLogLog();
	// implicit copying of HyperLogLog is not allowed
	HyperLogLog(const HyperLogLog &) = delete;

	//! Adds an element of the specified size to the HyperLogLog counter
	void Add(data_ptr_t element, idx_t size);
	//! Return the count of this HyperLogLog counter
	idx_t Count() const;
	//! Merge this HyperLogLog counter with another counter to create a new one
	unique_ptr<HyperLogLog> Merge(HyperLogLog &other);
	HyperLogLog *MergePointer(HyperLogLog &other);
	//! Merge a set of HyperLogLogs to create one big one
	static unique_ptr<HyperLogLog> Merge(HyperLogLog logs[], idx_t count);
	//! Get the size (in bytes) of a HLL
	static idx_t GetSize();
	//! Get pointer to the HLL
	data_ptr_t GetPtr() const;
	//! Get copy of the HLL
	unique_ptr<HyperLogLog> Copy();
	//! (De)Serialize the HLL
	void Serialize(FieldWriter &writer) const;
	static unique_ptr<HyperLogLog> Deserialize(FieldReader &reader);

public:
	//! Compute HLL hashes over vdata, and store them in 'hashes'
	//! Then, compute register indices and prefix lengths, and also store them in 'hashes' as a pair of uint32_t
	static void ProcessEntries(VectorData &vdata, const LogicalType &type, uint64_t hashes[], uint8_t counts[],
	                           idx_t count);
	//! Add the indices and counts to the logs
	static void AddToLogs(VectorData &vdata, idx_t count, uint64_t indices[], uint8_t counts[], HyperLogLog **logs[],
	                      const SelectionVector *log_sel);
	//! Add the indices and counts to THIS log
	void AddToLog(VectorData &vdata, idx_t count, uint64_t indices[], uint8_t counts[]);

private:
	explicit HyperLogLog(void *hll);

	void *hll;
	mutex lock;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/enums/date_part_specifier.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

enum class DatePartSpecifier : uint8_t {
	YEAR,
	MONTH,
	DAY,
	DECADE,
	CENTURY,
	MILLENNIUM,
	MICROSECONDS,
	MILLISECONDS,
	SECOND,
	MINUTE,
	HOUR,
	EPOCH,
	DOW,
	ISODOW,
	WEEK,
	ISOYEAR,
	QUARTER,
	DOY,
	YEARWEEK,
	ERA,
	TIMEZONE,
	TIMEZONE_HOUR,
	TIMEZONE_MINUTE
};

DUCKDB_API bool TryGetDatePartSpecifier(const string &specifier, DatePartSpecifier &result);
DUCKDB_API DatePartSpecifier GetDatePartSpecifier(const string &specifier);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/add.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct AddOperator {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		return left + right;
	}
};

template <>
float AddOperator::Operation(float left, float right);
template <>
double AddOperator::Operation(double left, double right);
template <>
date_t AddOperator::Operation(date_t left, int32_t right);
template <>
date_t AddOperator::Operation(int32_t left, date_t right);
template <>
timestamp_t AddOperator::Operation(date_t left, dtime_t right);
template <>
timestamp_t AddOperator::Operation(dtime_t left, date_t right);
template <>
interval_t AddOperator::Operation(interval_t left, interval_t right);
template <>
date_t AddOperator::Operation(date_t left, interval_t right);
template <>
date_t AddOperator::Operation(interval_t left, date_t right);
template <>
timestamp_t AddOperator::Operation(timestamp_t left, interval_t right);
template <>
timestamp_t AddOperator::Operation(interval_t left, timestamp_t right);

struct TryAddOperator {
	template <class TA, class TB, class TR>
	static inline bool Operation(TA left, TB right, TR &result) {
		throw InternalException("Unimplemented type for TryAddOperator");
	}
};

template <>
bool TryAddOperator::Operation(uint8_t left, uint8_t right, uint8_t &result);
template <>
bool TryAddOperator::Operation(uint16_t left, uint16_t right, uint16_t &result);
template <>
bool TryAddOperator::Operation(uint32_t left, uint32_t right, uint32_t &result);
template <>
bool TryAddOperator::Operation(uint64_t left, uint64_t right, uint64_t &result);

template <>
bool TryAddOperator::Operation(int8_t left, int8_t right, int8_t &result);
template <>
bool TryAddOperator::Operation(int16_t left, int16_t right, int16_t &result);
template <>
bool TryAddOperator::Operation(int32_t left, int32_t right, int32_t &result);
template <>
DUCKDB_API bool TryAddOperator::Operation(int64_t left, int64_t right, int64_t &result);

struct AddOperatorOverflowCheck {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		TR result;
		if (!TryAddOperator::Operation(left, right, result)) {
			throw OutOfRangeException("Overflow in addition of %s (%d + %d)!", TypeIdToString(GetTypeId<TA>()), left,
			                          right);
		}
		return result;
	}
};

struct TryDecimalAdd {
	template <class TA, class TB, class TR>
	static inline bool Operation(TA left, TB right, TR &result) {
		throw InternalException("Unimplemented type for TryDecimalAdd");
	}
};

template <>
bool TryDecimalAdd::Operation(int16_t left, int16_t right, int16_t &result);
template <>
bool TryDecimalAdd::Operation(int32_t left, int32_t right, int32_t &result);
template <>
bool TryDecimalAdd::Operation(int64_t left, int64_t right, int64_t &result);
template <>
bool TryDecimalAdd::Operation(hugeint_t left, hugeint_t right, hugeint_t &result);

struct DecimalAddOverflowCheck {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		TR result;
		if (!TryDecimalAdd::Operation<TA, TB, TR>(left, right, result)) {
			throw OutOfRangeException("Overflow in addition of DECIMAL(18) (%d + %d). You might want to add an "
			                          "explicit cast to a bigger decimal.",
			                          left, right);
		}
		return result;
	}
};

template <>
hugeint_t DecimalAddOverflowCheck::Operation(hugeint_t left, hugeint_t right);

struct AddTimeOperator {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right);
};

template <>
dtime_t AddTimeOperator::Operation(dtime_t left, interval_t right);
template <>
dtime_t AddTimeOperator::Operation(interval_t left, dtime_t right);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/subtract.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct SubtractOperator {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		return left - right;
	}
};

template <>
float SubtractOperator::Operation(float left, float right);
template <>
double SubtractOperator::Operation(double left, double right);
template <>
interval_t SubtractOperator::Operation(interval_t left, interval_t right);
template <>
int64_t SubtractOperator::Operation(date_t left, date_t right);
template <>
date_t SubtractOperator::Operation(date_t left, int32_t right);
template <>
date_t SubtractOperator::Operation(date_t left, interval_t right);
template <>
timestamp_t SubtractOperator::Operation(timestamp_t left, interval_t right);
template <>
interval_t SubtractOperator::Operation(timestamp_t left, timestamp_t right);

struct TrySubtractOperator {
	template <class TA, class TB, class TR>
	static inline bool Operation(TA left, TB right, TR &result) {
		throw InternalException("Unimplemented type for TrySubtractOperator");
	}
};

template <>
bool TrySubtractOperator::Operation(uint8_t left, uint8_t right, uint8_t &result);
template <>
bool TrySubtractOperator::Operation(uint16_t left, uint16_t right, uint16_t &result);
template <>
bool TrySubtractOperator::Operation(uint32_t left, uint32_t right, uint32_t &result);
template <>
bool TrySubtractOperator::Operation(uint64_t left, uint64_t right, uint64_t &result);

template <>
bool TrySubtractOperator::Operation(int8_t left, int8_t right, int8_t &result);
template <>
bool TrySubtractOperator::Operation(int16_t left, int16_t right, int16_t &result);
template <>
bool TrySubtractOperator::Operation(int32_t left, int32_t right, int32_t &result);
template <>
bool TrySubtractOperator::Operation(int64_t left, int64_t right, int64_t &result);
template <>
bool TrySubtractOperator::Operation(hugeint_t left, hugeint_t right, hugeint_t &result);

struct SubtractOperatorOverflowCheck {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		TR result;
		if (!TrySubtractOperator::Operation(left, right, result)) {
			throw OutOfRangeException("Overflow in subtraction of %s (%d - %d)!", TypeIdToString(GetTypeId<TA>()), left,
			                          right);
		}
		return result;
	}
};

struct TryDecimalSubtract {
	template <class TA, class TB, class TR>
	static inline bool Operation(TA left, TB right, TR &result) {
		throw InternalException("Unimplemented type for TryDecimalSubtract");
	}
};

template <>
bool TryDecimalSubtract::Operation(int16_t left, int16_t right, int16_t &result);
template <>
bool TryDecimalSubtract::Operation(int32_t left, int32_t right, int32_t &result);
template <>
bool TryDecimalSubtract::Operation(int64_t left, int64_t right, int64_t &result);
template <>
bool TryDecimalSubtract::Operation(hugeint_t left, hugeint_t right, hugeint_t &result);

struct DecimalSubtractOverflowCheck {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		TR result;
		if (!TryDecimalSubtract::Operation<TA, TB, TR>(left, right, result)) {
			throw OutOfRangeException("Overflow in subtract of DECIMAL(18) (%d - %d). You might want to add an "
			                          "explicit cast to a bigger decimal.",
			                          left, right);
		}
		return result;
	}
};

template <>
hugeint_t DecimalSubtractOverflowCheck::Operation(hugeint_t left, hugeint_t right);

struct SubtractTimeOperator {
	template <class TA, class TB, class TR>
	static TR Operation(TA left, TB right);
};

template <>
dtime_t SubtractTimeOperator::Operation(dtime_t left, interval_t right);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/aggregate_operators.hpp
//
//
//===----------------------------------------------------------------------===//



#include <algorithm>
#include <cstdint>
#include <cstring>


namespace duckdb {

struct Min {
	template <class T>
	static inline T Operation(T left, T right) {
		return LessThan::Operation(left, right) ? left : right;
	}
};

struct Max {
	template <class T>
	static inline T Operation(T left, T right) {
		return GreaterThan::Operation(left, right) ? left : right;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/numeric_binary_operators.hpp
//
//
//===----------------------------------------------------------------------===//




#include <cmath>

namespace duckdb {

struct DivideOperator {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		D_ASSERT(right != 0); // this should be checked before!
		return left / right;
	}
};

struct ModuloOperator {
	template <class TA, class TB, class TR>
	static inline TR Operation(TA left, TB right) {
		D_ASSERT(right != 0);
		return left % right;
	}
};

template <>
float DivideOperator::Operation(float left, float right);
template <>
double DivideOperator::Operation(double left, double right);
template <>
hugeint_t DivideOperator::Operation(hugeint_t left, hugeint_t right);
template <>
interval_t DivideOperator::Operation(interval_t left, int64_t right);

template <>
float ModuloOperator::Operation(float left, float right);
template <>
double ModuloOperator::Operation(double left, double right);
template <>
hugeint_t ModuloOperator::Operation(hugeint_t left, hugeint_t right);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/nested_functions.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

enum class MapInvalidReason : uint8_t { VALID, NULL_KEY_LIST, NULL_KEY, DUPLICATE_KEY };

struct VariableReturnBindData : public FunctionData {
	LogicalType stype;

	explicit VariableReturnBindData(const LogicalType &stype_p) : stype(stype_p) {
	}

	unique_ptr<FunctionData> Copy() const override {
		return make_unique<VariableReturnBindData>(stype);
	}
	bool Equals(const FunctionData &other_p) const override {
		auto &other = (const VariableReturnBindData &)other_p;
		return stype == other.stype;
	}
};

template <class T, class MAP_TYPE = map<T, idx_t>>
struct HistogramAggState {
	MAP_TYPE *hist;
};

struct ArraySliceFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StructPackFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StructInsertFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListValueFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListRangeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MapFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MapExtractFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListExtractFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListConcatFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListContainsFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListFlattenFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListPositionFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListAggregateFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListDistinctFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListUniqueFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ListSortFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CardinalityFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StructExtractFun {
	static ScalarFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

MapInvalidReason CheckMapValidity(Vector &map, idx_t count,
                                  const SelectionVector &sel = *FlatVector::IncrementalSelectionVector());

} // 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)
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_operations/decimal_cast.hpp
//
//
//===----------------------------------------------------------------------===//



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






namespace duckdb {

struct HandleVectorCastError {
	template <class RESULT_TYPE>
	static RESULT_TYPE Operation(string error_message, ValidityMask &mask, idx_t idx, string *error_message_ptr,
	                             bool &all_converted) {
		HandleCastError::AssignError(error_message, error_message_ptr);
		all_converted = false;
		mask.SetInvalid(idx);
		return NullValue<RESULT_TYPE>();
	}
};

static string UnimplementedCastMessage(const LogicalType &source_type, const LogicalType &target_type) {
	return StringUtil::Format("Unimplemented type for cast (%s -> %s)", source_type.ToString(), target_type.ToString());
}

// NULL cast only works if all values in source are NULL, otherwise an unimplemented cast exception is thrown
static bool TryVectorNullCast(Vector &source, Vector &result, idx_t count, string *error_message) {
	bool success = true;
	if (VectorOperations::HasNotNull(source, count)) {
		HandleCastError::AssignError(UnimplementedCastMessage(source.GetType(), result.GetType()), error_message);
		success = false;
	}
	result.SetVectorType(VectorType::CONSTANT_VECTOR);
	ConstantVector::SetNull(result, true);
	return success;
}

} // namespace duckdb




namespace duckdb {

struct VectorDecimalCastData {
	VectorDecimalCastData(string *error_message_p, uint8_t width_p, uint8_t scale_p)
	    : error_message(error_message_p), width(width_p), scale(scale_p) {
	}

	string *error_message;
	uint8_t width;
	uint8_t scale;
	bool all_converted = true;
};

template <class OP>
struct VectorDecimalCastOperator {
	template <class INPUT_TYPE, class RESULT_TYPE>
	static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto data = (VectorDecimalCastData *)dataptr;
		RESULT_TYPE result_value;
		if (!OP::template Operation<INPUT_TYPE, RESULT_TYPE>(input, result_value, data->error_message, data->width,
		                                                     data->scale)) {
			return HandleVectorCastError::Operation<RESULT_TYPE>("Failed to cast decimal value", mask, idx,
			                                                     data->error_message, data->all_converted);
		}
		return result_value;
	}
};

template <class SRC, class T, class OP>
bool TemplatedVectorDecimalCast(Vector &source, Vector &result, idx_t count, string *error_message, uint8_t width,
                                uint8_t scale) {
	VectorDecimalCastData input(error_message, width, scale);
	UnaryExecutor::GenericExecute<SRC, T, VectorDecimalCastOperator<OP>>(source, result, count, (void *)&input,
	                                                                     error_message);
	return input.all_converted;
}

template <class T>
static bool ToDecimalCast(Vector &source, Vector &result, idx_t count, string *error_message) {
	auto &result_type = result.GetType();
	auto width = DecimalType::GetWidth(result_type);
	auto scale = DecimalType::GetScale(result_type);
	switch (result_type.InternalType()) {
	case PhysicalType::INT16:
		return TemplatedVectorDecimalCast<T, int16_t, TryCastToDecimal>(source, result, count, error_message, width,
		                                                                scale);
	case PhysicalType::INT32:
		return TemplatedVectorDecimalCast<T, int32_t, TryCastToDecimal>(source, result, count, error_message, width,
		                                                                scale);
	case PhysicalType::INT64:
		return TemplatedVectorDecimalCast<T, int64_t, TryCastToDecimal>(source, result, count, error_message, width,
		                                                                scale);
	case PhysicalType::INT128:
		return TemplatedVectorDecimalCast<T, hugeint_t, TryCastToDecimal>(source, result, count, error_message, width,
		                                                                  scale);
	default:
		throw InternalException("Unimplemented internal type for decimal");
	}
}

template <class T>
static bool FromDecimalCast(Vector &source, Vector &result, idx_t count, string *error_message) {
	auto &source_type = source.GetType();
	auto width = DecimalType::GetWidth(source_type);
	auto scale = DecimalType::GetScale(source_type);
	switch (source_type.InternalType()) {
	case PhysicalType::INT16:
		return TemplatedVectorDecimalCast<int16_t, T, TryCastFromDecimal>(source, result, count, error_message, width,
		                                                                  scale);
	case PhysicalType::INT32:
		return TemplatedVectorDecimalCast<int32_t, T, TryCastFromDecimal>(source, result, count, error_message, width,
		                                                                  scale);
	case PhysicalType::INT64:
		return TemplatedVectorDecimalCast<int64_t, T, TryCastFromDecimal>(source, result, count, error_message, width,
		                                                                  scale);
	case PhysicalType::INT128:
		return TemplatedVectorDecimalCast<hugeint_t, T, TryCastFromDecimal>(source, result, count, error_message, width,
		                                                                    scale);
	default:
		throw InternalException("Unimplemented internal type for decimal");
	}
}

template <class LIMIT_TYPE, class FACTOR_TYPE = LIMIT_TYPE>
struct DecimalScaleInput {
	DecimalScaleInput(Vector &result_p, FACTOR_TYPE factor_p) : result(result_p), factor(factor_p) {
	}
	DecimalScaleInput(Vector &result_p, LIMIT_TYPE limit_p, FACTOR_TYPE factor_p, string *error_message_p,
	                  uint8_t source_scale_p)
	    : result(result_p), limit(limit_p), factor(factor_p), error_message(error_message_p),
	      source_scale(source_scale_p) {
	}

	Vector &result;
	LIMIT_TYPE limit;
	FACTOR_TYPE factor;
	bool all_converted = true;
	string *error_message;
	uint8_t source_scale;
};

struct DecimalScaleUpOperator {
	template <class INPUT_TYPE, class RESULT_TYPE>
	static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto data = (DecimalScaleInput<INPUT_TYPE, RESULT_TYPE> *)dataptr;
		return Cast::Operation<INPUT_TYPE, RESULT_TYPE>(input) * data->factor;
	}
};

struct DecimalScaleUpCheckOperator {
	template <class INPUT_TYPE, class RESULT_TYPE>
	static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto data = (DecimalScaleInput<INPUT_TYPE, RESULT_TYPE> *)dataptr;
		if (input >= data->limit || input <= -data->limit) {
			auto error =
			    StringUtil::Format("Casting value \"%s\" to type %s failed: value is out of range!",
			                       Decimal::ToString(input, data->source_scale), data->result.GetType().ToString());
			return HandleVectorCastError::Operation<RESULT_TYPE>(move(error), mask, idx, data->error_message,
			                                                     data->all_converted);
		}
		return Cast::Operation<INPUT_TYPE, RESULT_TYPE>(input) * data->factor;
	}
};

template <class SOURCE, class DEST, class POWERS_SOURCE, class POWERS_DEST>
bool TemplatedDecimalScaleUp(Vector &source, Vector &result, idx_t count, string *error_message) {
	auto source_scale = DecimalType::GetScale(source.GetType());
	auto source_width = DecimalType::GetWidth(source.GetType());
	auto result_scale = DecimalType::GetScale(result.GetType());
	auto result_width = DecimalType::GetWidth(result.GetType());
	D_ASSERT(result_scale >= source_scale);
	idx_t scale_difference = result_scale - source_scale;
	DEST multiply_factor = POWERS_DEST::POWERS_OF_TEN[scale_difference];
	idx_t target_width = result_width - scale_difference;
	if (source_width < target_width) {
		DecimalScaleInput<SOURCE, DEST> input(result, multiply_factor);
		// type will always fit: no need to check limit
		UnaryExecutor::GenericExecute<SOURCE, DEST, DecimalScaleUpOperator>(source, result, count, &input);
		return true;
	} else {
		// type might not fit: check limit
		auto limit = POWERS_SOURCE::POWERS_OF_TEN[target_width];
		DecimalScaleInput<SOURCE, DEST> input(result, limit, multiply_factor, error_message, source_scale);
		UnaryExecutor::GenericExecute<SOURCE, DEST, DecimalScaleUpCheckOperator>(source, result, count, &input,
		                                                                         error_message);
		return input.all_converted;
	}
}

struct DecimalScaleDownOperator {
	template <class INPUT_TYPE, class RESULT_TYPE>
	static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto data = (DecimalScaleInput<INPUT_TYPE> *)dataptr;
		return Cast::Operation<INPUT_TYPE, RESULT_TYPE>(input / data->factor);
	}
};

struct DecimalScaleDownCheckOperator {
	template <class INPUT_TYPE, class RESULT_TYPE>
	static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto data = (DecimalScaleInput<INPUT_TYPE> *)dataptr;
		if (input >= data->limit || input <= -data->limit) {
			auto error =
			    StringUtil::Format("Casting value \"%s\" to type %s failed: value is out of range!",
			                       Decimal::ToString(input, data->source_scale), data->result.GetType().ToString());
			return HandleVectorCastError::Operation<RESULT_TYPE>(move(error), mask, idx, data->error_message,
			                                                     data->all_converted);
		}
		return Cast::Operation<INPUT_TYPE, RESULT_TYPE>(input / data->factor);
	}
};

template <class SOURCE, class DEST, class POWERS_SOURCE>
bool TemplatedDecimalScaleDown(Vector &source, Vector &result, idx_t count, string *error_message) {
	auto source_scale = DecimalType::GetScale(source.GetType());
	auto source_width = DecimalType::GetWidth(source.GetType());
	auto result_scale = DecimalType::GetScale(result.GetType());
	auto result_width = DecimalType::GetWidth(result.GetType());
	D_ASSERT(result_scale < source_scale);
	idx_t scale_difference = source_scale - result_scale;
	idx_t target_width = result_width + scale_difference;
	SOURCE divide_factor = POWERS_SOURCE::POWERS_OF_TEN[scale_difference];
	if (source_width < target_width) {
		DecimalScaleInput<SOURCE> input(result, divide_factor);
		// type will always fit: no need to check limit
		UnaryExecutor::GenericExecute<SOURCE, DEST, DecimalScaleDownOperator>(source, result, count, &input);
		return true;
	} else {
		// type might not fit: check limit
		auto limit = POWERS_SOURCE::POWERS_OF_TEN[target_width];
		DecimalScaleInput<SOURCE> input(result, limit, divide_factor, error_message, source_scale);
		UnaryExecutor::GenericExecute<SOURCE, DEST, DecimalScaleDownCheckOperator>(source, result, count, &input,
		                                                                           error_message);
		return input.all_converted;
	}
}

template <class SOURCE, class POWERS_SOURCE>
static bool DecimalDecimalCastSwitch(Vector &source, Vector &result, idx_t count, string *error_message) {
	auto source_scale = DecimalType::GetScale(source.GetType());
	auto result_scale = DecimalType::GetScale(result.GetType());
	source.GetType().Verify();
	result.GetType().Verify();

	// we need to either multiply or divide by the difference in scales
	if (result_scale >= source_scale) {
		// multiply
		switch (result.GetType().InternalType()) {
		case PhysicalType::INT16:
			return TemplatedDecimalScaleUp<SOURCE, int16_t, POWERS_SOURCE, NumericHelper>(source, result, count,
			                                                                              error_message);
		case PhysicalType::INT32:
			return TemplatedDecimalScaleUp<SOURCE, int32_t, POWERS_SOURCE, NumericHelper>(source, result, count,
			                                                                              error_message);
		case PhysicalType::INT64:
			return TemplatedDecimalScaleUp<SOURCE, int64_t, POWERS_SOURCE, NumericHelper>(source, result, count,
			                                                                              error_message);
		case PhysicalType::INT128:
			return TemplatedDecimalScaleUp<SOURCE, hugeint_t, POWERS_SOURCE, Hugeint>(source, result, count,
			                                                                          error_message);
		default:
			throw NotImplementedException("Unimplemented internal type for decimal");
		}
	} else {
		// divide
		switch (result.GetType().InternalType()) {
		case PhysicalType::INT16:
			return TemplatedDecimalScaleDown<SOURCE, int16_t, POWERS_SOURCE>(source, result, count, error_message);
		case PhysicalType::INT32:
			return TemplatedDecimalScaleDown<SOURCE, int32_t, POWERS_SOURCE>(source, result, count, error_message);
		case PhysicalType::INT64:
			return TemplatedDecimalScaleDown<SOURCE, int64_t, POWERS_SOURCE>(source, result, count, error_message);
		case PhysicalType::INT128:
			return TemplatedDecimalScaleDown<SOURCE, hugeint_t, POWERS_SOURCE>(source, result, count, error_message);
		default:
			throw NotImplementedException("Unimplemented internal type for decimal");
		}
	}
}

struct DecimalCastInput {
	DecimalCastInput(Vector &result_p, uint8_t width_p, uint8_t scale_p)
	    : result(result_p), width(width_p), scale(scale_p) {
	}

	Vector &result;
	uint8_t width;
	uint8_t scale;
};

struct StringCastFromDecimalOperator {
	template <class INPUT_TYPE, class RESULT_TYPE>
	static RESULT_TYPE Operation(INPUT_TYPE input, ValidityMask &mask, idx_t idx, void *dataptr) {
		auto data = (DecimalCastInput *)dataptr;
		return StringCastFromDecimal::Operation<INPUT_TYPE>(input, data->width, data->scale, data->result);
	}
};

static bool DecimalCastSwitch(Vector &source, Vector &result, idx_t count, string *error_message) {
	// now switch on the result type
	switch (result.GetType().id()) {
	case LogicalTypeId::BOOLEAN:
		return FromDecimalCast<bool>(source, result, count, error_message);
	case LogicalTypeId::TINYINT:
		return FromDecimalCast<int8_t>(source, result, count, error_message);
	case LogicalTypeId::SMALLINT:
		return FromDecimalCast<int16_t>(source, result, count, error_message);
	case LogicalTypeId::INTEGER:
		return FromDecimalCast<int32_t>(source, result, count, error_message);
	case LogicalTypeId::BIGINT:
		return FromDecimalCast<int64_t>(source, result, count, error_message);
	case LogicalTypeId::UTINYINT:
		return FromDecimalCast<uint8_t>(source, result, count, error_message);
	case LogicalTypeId::USMALLINT:
		return FromDecimalCast<uint16_t>(source, result, count, error_message);
	case LogicalTypeId::UINTEGER:
		return FromDecimalCast<uint32_t>(source, result, count, error_message);
	case LogicalTypeId::UBIGINT:
		return FromDecimalCast<uint64_t>(source, result, count, error_message);
	case LogicalTypeId::HUGEINT:
		return FromDecimalCast<hugeint_t>(source, result, count, error_message);
	case LogicalTypeId::DECIMAL: {
		// decimal to decimal cast
		// first we need to figure out the source and target internal types
		switch (source.GetType().InternalType()) {
		case PhysicalType::INT16:
			return DecimalDecimalCastSwitch<int16_t, NumericHelper>(source, result, count, error_message);
		case PhysicalType::INT32:
			return DecimalDecimalCastSwitch<int32_t, NumericHelper>(source, result, count, error_message);
		case PhysicalType::INT64:
			return DecimalDecimalCastSwitch<int64_t, NumericHelper>(source, result, count, error_message);
		case PhysicalType::INT128:
			return DecimalDecimalCastSwitch<hugeint_t, Hugeint>(source, result, count, error_message);
		default:
			throw NotImplementedException("Unimplemented internal type for decimal in decimal_decimal cast");
		}
		break;
	}
	case LogicalTypeId::FLOAT:
		return FromDecimalCast<float>(source, result, count, error_message);
	case LogicalTypeId::DOUBLE:
		return FromDecimalCast<double>(source, result, count, error_message);
	case LogicalTypeId::VARCHAR: {
		auto &source_type = source.GetType();
		auto width = DecimalType::GetWidth(source_type);
		auto scale = DecimalType::GetScale(source_type);
		DecimalCastInput input(result, width, scale);
		switch (source_type.InternalType()) {
		case PhysicalType::INT16:
			UnaryExecutor::GenericExecute<int16_t, string_t, StringCastFromDecimalOperator>(source, result, count,
			                                                                                (void *)&input);
			break;
		case PhysicalType::INT32:
			UnaryExecutor::GenericExecute<int32_t, string_t, StringCastFromDecimalOperator>(source, result, count,
			                                                                                (void *)&input);
			break;
		case PhysicalType::INT64:
			UnaryExecutor::GenericExecute<int64_t, string_t, StringCastFromDecimalOperator>(source, result, count,
			                                                                                (void *)&input);
			break;
		case PhysicalType::INT128:
			UnaryExecutor::GenericExecute<hugeint_t, string_t, StringCastFromDecimalOperator>(source, result, count,
			                                                                                  (void *)&input);
			break;
		default:
			throw InternalException("Unimplemented internal decimal type");
		}
		return true;
	}
	default:
		return TryVectorNullCast(source, result, count, error_message);
	}
}

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/virtual_file_system.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

// bunch of wrappers to allow registering protocol handlers
class VirtualFileSystem : public FileSystem {
public:
	VirtualFileSystem();

	unique_ptr<FileHandle> OpenFile(const string &path, uint8_t flags, FileLockType lock = FileLockType::NO_LOCK,
	                                FileCompressionType compression = FileCompressionType::UNCOMPRESSED,
	                                FileOpener *opener = nullptr) override;

	void Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override {
		handle.file_system.Read(handle, buffer, nr_bytes, location);
	};

	void Write(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) override {
		handle.file_system.Write(handle, buffer, nr_bytes, location);
	}

	int64_t Read(FileHandle &handle, void *buffer, int64_t nr_bytes) override {
		return handle.file_system.Read(handle, buffer, nr_bytes);
	}

	int64_t Write(FileHandle &handle, void *buffer, int64_t nr_bytes) override {
		return handle.file_system.Write(handle, buffer, nr_bytes);
	}

	int64_t GetFileSize(FileHandle &handle) override {
		return handle.file_system.GetFileSize(handle);
	}
	time_t GetLastModifiedTime(FileHandle &handle) override {
		return handle.file_system.GetLastModifiedTime(handle);
	}
	FileType GetFileType(FileHandle &handle) override {
		return handle.file_system.GetFileType(handle);
	}

	void Truncate(FileHandle &handle, int64_t new_size) override {
		handle.file_system.Truncate(handle, new_size);
	}

	void FileSync(FileHandle &handle) override {
		handle.file_system.FileSync(handle);
	}

	// need to look up correct fs for this
	bool DirectoryExists(const string &directory) override {
		return FindFileSystem(directory)->DirectoryExists(directory);
	}
	void CreateDirectory(const string &directory) override {
		FindFileSystem(directory)->CreateDirectory(directory);
	}

	void RemoveDirectory(const string &directory) override {
		FindFileSystem(directory)->RemoveDirectory(directory);
	}

	bool ListFiles(const string &directory, const std::function<void(const string &, bool)> &callback) override {
		return FindFileSystem(directory)->ListFiles(directory, callback);
	}

	void MoveFile(const string &source, const string &target) override {
		FindFileSystem(source)->MoveFile(source, target);
	}

	bool FileExists(const string &filename) override {
		return FindFileSystem(filename)->FileExists(filename);
	}

	bool IsPipe(const string &filename) override {
		return FindFileSystem(filename)->IsPipe(filename);
	}
	virtual void RemoveFile(const string &filename) override {
		FindFileSystem(filename)->RemoveFile(filename);
	}

	virtual vector<string> Glob(const string &path, FileOpener *opener = nullptr) override {
		return FindFileSystem(path)->Glob(path, opener);
	}

	void RegisterSubSystem(unique_ptr<FileSystem> fs) override {
		sub_systems.push_back(move(fs));
	}

	void RegisterSubSystem(FileCompressionType compression_type, unique_ptr<FileSystem> fs) override {
		compressed_fs[compression_type] = move(fs);
	}

	std::string GetName() const override {
		return "VirtualFileSystem";
	}

private:
	FileSystem *FindFileSystem(const string &path) {
		for (auto &sub_system : sub_systems) {
			if (sub_system->CanHandleFile(path)) {
				return sub_system.get();
			}
		}
		return default_fs.get();
	}

private:
	vector<unique_ptr<FileSystem>> sub_systems;
	map<FileCompressionType, unique_ptr<FileSystem>> compressed_fs;
	const unique_ptr<FileSystem> default_fs;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/column_binding_resolver.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/column_binding_map.hpp
//
//
//===----------------------------------------------------------------------===//








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



namespace duckdb {

//! The ColumnBindingResolver resolves ColumnBindings into base tables
//! (table_index, column_index) into physical indices into the DataChunks that
//! are used within the execution engine
class ColumnBindingResolver : public LogicalOperatorVisitor {
public:
	ColumnBindingResolver();

	void VisitOperator(LogicalOperator &op) override;

protected:
	vector<ColumnBinding> bindings;

	unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr) override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_comparison_join.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);

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, unordered_set<idx_t> &left_bindings,
	                            unordered_set<uint64_t> &right_bindings);
	static JoinSide GetJoinSide(Expression &expression, unordered_set<idx_t> &left_bindings,
	                            unordered_set<idx_t> &right_bindings);
	static JoinSide GetJoinSide(const unordered_set<idx_t> &bindings, unordered_set<idx_t> &left_bindings,
	                            unordered_set<idx_t> &right_bindings);

private:
	JoinValue value;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_join.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

//! LogicalJoin represents a join between two relations
class LogicalJoin : public LogicalOperator {
public:
	explicit LogicalJoin(JoinType type, LogicalOperatorType logical_type = LogicalOperatorType::LOGICAL_JOIN);

	// Gets the set of table references that are reachable from this node
	static void GetTableReferences(LogicalOperator &op, unordered_set<idx_t> &bindings);
	static void GetExpressionBindings(Expression &expr, unordered_set<idx_t> &bindings);

	//! The type of the join (INNER, OUTER, etc...)
	JoinType join_type;
	//! Table index used to refer to the MARK column (in case of a MARK join)
	idx_t mark_index;
	//! The columns of the LHS that are output by the join
	vector<idx_t> left_projection_map;
	//! The columns of the RHS that are output by the join
	vector<idx_t> right_projection_map;
	//! Join Keys statistics (optional)
	vector<unique_ptr<BaseStatistics>> join_stats;

public:
	vector<ColumnBinding> GetColumnBindings() override;

protected:
	void ResolveTypes() override;
};

} // namespace duckdb


namespace duckdb {

//! LogicalComparisonJoin represents a join that involves comparisons between the LHS and RHS
class LogicalComparisonJoin : public LogicalJoin {
public:
	explicit LogicalComparisonJoin(JoinType type,
	                               LogicalOperatorType logical_type = LogicalOperatorType::LOGICAL_COMPARISON_JOIN);

	//! The conditions of the join
	vector<JoinCondition> conditions;
	//! Used for duplicate-eliminated joins
	vector<LogicalType> delim_types;

public:
	string ParamsToString() const override;

public:
	static unique_ptr<LogicalOperator> CreateJoin(JoinType type, unique_ptr<LogicalOperator> left_child,
	                                              unique_ptr<LogicalOperator> right_child,
	                                              unordered_set<idx_t> &left_bindings,
	                                              unordered_set<idx_t> &right_bindings,
	                                              vector<unique_ptr<Expression>> &expressions);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_create_index.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class LogicalCreateIndex : public LogicalOperator {
public:
	LogicalCreateIndex(TableCatalogEntry &table, vector<column_t> column_ids,
	                   vector<unique_ptr<Expression>> expressions, unique_ptr<CreateIndexInfo> info)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_INDEX), table(table), column_ids(column_ids),
	      info(std::move(info)) {
		for (auto &expr : expressions) {
			this->unbound_expressions.push_back(expr->Copy());
		}
		this->expressions = move(expressions);
	}

	//! The table to create the index for
	TableCatalogEntry &table;
	//! Column IDs needed for index creation
	vector<column_t> column_ids;
	// Info for index creation
	unique_ptr<CreateIndexInfo> info;
	//! Unbound expressions to be used in the optimizer
	vector<unique_ptr<Expression>> unbound_expressions;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BIGINT);
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_delim_join.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalDelimJoin represents a special "duplicate eliminated" join. This join type is only used for subquery
//! flattening, and involves performing duplicate elimination on the LEFT side which is then pushed into the RIGHT side.
class LogicalDelimJoin : public LogicalComparisonJoin {
public:
	explicit LogicalDelimJoin(JoinType type) : LogicalComparisonJoin(type, LogicalOperatorType::LOGICAL_DELIM_JOIN) {
	}

	//! The set of columns that will be duplicate eliminated from the LHS and pushed into the RHS
	vector<unique_ptr<Expression>> duplicate_eliminated_columns;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/join_hashtable.hpp
//
//
//===----------------------------------------------------------------------===//













namespace duckdb {
class BufferManager;
class BufferHandle;

struct JoinHTScanState {
	JoinHTScanState() : position(0), block_position(0) {
	}

	idx_t position;
	idx_t block_position;
	mutex lock;
};

//! JoinHashTable is a linear probing HT that is used for computing joins
/*!
   The JoinHashTable concatenates incoming chunks inside a linked list of
   data ptrs. The storage looks like this internally.
   [SERIALIZED ROW][NEXT POINTER]
   [SERIALIZED ROW][NEXT POINTER]
   There is a separate hash map of pointers that point into this table.
   This is what is used to resolve the hashes.
   [POINTER]
   [POINTER]
   [POINTER]
   The pointers are either NULL
*/
class JoinHashTable {
public:
	using ValidityBytes = TemplatedValidityMask<uint8_t>;

	//! Scan structure that can be used to resume scans, as a single probe can
	//! return 1024*N values (where N is the size of the HT). This is
	//! returned by the JoinHashTable::Scan function and can be used to resume a
	//! probe.
	struct ScanStructure {
		unique_ptr<VectorData[]> key_data;
		Vector pointers;
		idx_t count;
		SelectionVector sel_vector;
		// whether or not the given tuple has found a match
		unique_ptr<bool[]> found_match;
		JoinHashTable &ht;
		bool finished;

		explicit ScanStructure(JoinHashTable &ht);
		//! Get the next batch of data from the scan structure
		void Next(DataChunk &keys, DataChunk &left, DataChunk &result);

	private:
		//! Next operator for the inner join
		void NextInnerJoin(DataChunk &keys, DataChunk &left, DataChunk &result);
		//! Next operator for the semi join
		void NextSemiJoin(DataChunk &keys, DataChunk &left, DataChunk &result);
		//! Next operator for the anti join
		void NextAntiJoin(DataChunk &keys, DataChunk &left, DataChunk &result);
		//! Next operator for the left outer join
		void NextLeftJoin(DataChunk &keys, DataChunk &left, DataChunk &result);
		//! Next operator for the mark join
		void NextMarkJoin(DataChunk &keys, DataChunk &left, DataChunk &result);
		//! Next operator for the single join
		void NextSingleJoin(DataChunk &keys, DataChunk &left, DataChunk &result);

		//! Scan the hashtable for matches of the specified keys, setting the found_match[] array to true or false
		//! for every tuple
		void ScanKeyMatches(DataChunk &keys);
		template <bool MATCH>
		void NextSemiOrAntiJoin(DataChunk &keys, DataChunk &left, DataChunk &result);

		void ConstructMarkJoinResult(DataChunk &join_keys, DataChunk &child, DataChunk &result);

		idx_t ScanInnerJoin(DataChunk &keys, SelectionVector &result_vector);

		idx_t ResolvePredicates(DataChunk &keys, SelectionVector &match_sel);
		idx_t ResolvePredicates(DataChunk &keys, SelectionVector &match_sel, SelectionVector &no_match_sel);

	public:
		void AdvancePointers();
		void AdvancePointers(const SelectionVector &sel, idx_t sel_count);
		void GatherResult(Vector &result, const SelectionVector &result_vector, const SelectionVector &sel_vector,
		                  const idx_t count, const idx_t col_idx);
		void GatherResult(Vector &result, const SelectionVector &sel_vector, const idx_t count, const idx_t col_idx);
		idx_t ResolvePredicates(DataChunk &keys, SelectionVector &match_sel, SelectionVector *no_match_sel);
	};

private:
public:
	JoinHashTable(BufferManager &buffer_manager, const vector<JoinCondition> &conditions,
	              vector<LogicalType> build_types, JoinType type);
	~JoinHashTable();

	//! Add the given data to the HT
	void Build(DataChunk &keys, DataChunk &input);
	//! Finalize the build of the HT, constructing the actual hash table and making the HT ready for probing.
	//! Finalize must be called before any call to Probe, and after Finalize is called Build should no longer be
	//! ever called.
	void Finalize();
	//! Probe the HT with the given input chunk, resulting in the given result
	unique_ptr<ScanStructure> Probe(DataChunk &keys);
	//! Scan the HT to construct the final full outer join result after
	void ScanFullOuter(DataChunk &result, JoinHTScanState &state);
	//! Fill the pointer with all the addresses from the hashtable for full scan
	idx_t FillWithHTOffsets(data_ptr_t *key_locations, JoinHTScanState &state);

	idx_t Count() {
		return block_collection->count;
	}

	//! BufferManager
	BufferManager &buffer_manager;
	//! The types of the keys used in equality comparison
	vector<LogicalType> equality_types;
	//! The types of the keys
	vector<LogicalType> condition_types;
	//! The types of all conditions
	vector<LogicalType> build_types;
	//! The comparison predicates
	vector<ExpressionType> predicates;
	//! Data column layout
	RowLayout layout;
	//! The size of an entry as stored in the HashTable
	idx_t entry_size;
	//! The total tuple size
	idx_t tuple_size;
	//! Next pointer offset in tuple
	idx_t pointer_offset;
	//! A constant false column for initialising right outer joins
	Vector vfound;
	//! The join type of the HT
	JoinType join_type;
	//! Whether or not the HT has been finalized
	bool finalized;
	//! Whether or not any of the key elements contain NULL
	bool has_null;
	//! Bitmask for getting relevant bits from the hashes to determine the position
	uint64_t bitmask;

	struct {
		mutex mj_lock;
		//! The types of the duplicate eliminated columns, only used in correlated MARK JOIN for flattening
		//! ANY()/ALL() expressions
		vector<LogicalType> correlated_types;
		//! The aggregate expression nodes used by the HT
		vector<unique_ptr<Expression>> correlated_aggregates;
		//! The HT that holds the group counts for every correlated column
		unique_ptr<GroupedAggregateHashTable> correlated_counts;
		//! Group chunk used for aggregating into correlated_counts
		DataChunk group_chunk;
		//! Payload chunk used for aggregating into correlated_counts
		DataChunk correlated_payload;
		//! Result chunk used for aggregating into correlated_counts
		DataChunk result_chunk;
	} correlated_mark_join_info;

private:
	void Hash(DataChunk &keys, const SelectionVector &sel, idx_t count, Vector &hashes);

	//! Apply a bitmask to the hashes
	void ApplyBitmask(Vector &hashes, idx_t count);
	void ApplyBitmask(Vector &hashes, const SelectionVector &sel, idx_t count, Vector &pointers);

private:
	//! Insert the given set of locations into the HT with the given set of
	//! hashes. Caller should hold lock in parallel HT.
	void InsertHashes(Vector &hashes, idx_t count, data_ptr_t key_locations[]);

	idx_t PrepareKeys(DataChunk &keys, unique_ptr<VectorData[]> &key_data, const SelectionVector *&current_sel,
	                  SelectionVector &sel, bool build_side);

	//! The RowDataCollection holding the main data of the hash table
	unique_ptr<RowDataCollection> block_collection;
	//! The stringheap of the JoinHashTable
	unique_ptr<RowDataCollection> string_heap;
	//! Pinned handles, these are pinned during finalization only
	vector<BufferHandle> pinned_handles;
	//! The hash map of the HT, created after finalization
	BufferHandle hash_map;
	//! Whether or not NULL values are considered equal in each of the comparisons
	vector<bool> null_values_are_equal;

	//! Copying not allowed
	JoinHashTable(const JoinHashTable &) = delete;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/nested_loop_join.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

struct NestedLoopJoinInner {
	static idx_t Perform(idx_t &ltuple, idx_t &rtuple, DataChunk &left_conditions, DataChunk &right_conditions,
	                     SelectionVector &lvector, SelectionVector &rvector, const vector<JoinCondition> &conditions);
};

struct NestedLoopJoinMark {
	static void Perform(DataChunk &left, ChunkCollection &right, bool found_match[],
	                    const vector<JoinCondition> &conditions);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/event.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Executor;
class Task;

class Event : public std::enable_shared_from_this<Event> {
public:
	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() {
		return total_dependencies != 0;
	}
	void CompleteDependency();

	void SetTasks(vector<unique_ptr<Task>> tasks);

	void InsertEvent(shared_ptr<Event> replacement_event);

	bool IsFinished() {
		return finished;
	}

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;

	//! Whether or not the event is finished executing
	atomic<bool> finished;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/aggregate/physical_perfecthash_aggregate.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ClientContext;
class PerfectAggregateHashTable;

//! PhysicalPerfectHashAggregate performs a group-by and aggregation using a perfect hash table
class PhysicalPerfectHashAggregate : public PhysicalOperator {
public:
	PhysicalPerfectHashAggregate(ClientContext &context, vector<LogicalType> types,
	                             vector<unique_ptr<Expression>> aggregates, vector<unique_ptr<Expression>> groups,
	                             vector<unique_ptr<BaseStatistics>> group_stats, vector<idx_t> required_bits,
	                             idx_t estimated_cardinality);

	//! The groups
	vector<unique_ptr<Expression>> groups;
	//! The aggregates that have to be computed
	vector<unique_ptr<Expression>> aggregates;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const override;

	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	string ParamsToString() const override;

	//! Create a perfect aggregate hash table for this node
	unique_ptr<PerfectAggregateHashTable> CreateHT(Allocator &allocator, ClientContext &context) const;

	bool IsSink() const override {
		return true;
	}

	bool ParallelSink() const override {
		return true;
	}

public:
	//! The group types
	vector<LogicalType> group_types;
	//! The payload types
	vector<LogicalType> payload_types;
	//! The aggregates to be computed
	vector<AggregateObject> aggregate_objects;
	//! The minimum value of each of the groups
	vector<Value> group_minima;
	//! The number of bits we need to completely cover each of the groups
	vector<idx_t> required_bits;

	unordered_map<Expression *, size_t> filter_indexes;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/perfect_aggregate_hashtable.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class PerfectAggregateHashTable : public BaseAggregateHashTable {
public:
	PerfectAggregateHashTable(Allocator &allocator, BufferManager &buffer_manager,
	                          const vector<LogicalType> &group_types, vector<LogicalType> payload_types_p,
	                          vector<AggregateObject> aggregate_objects, vector<Value> group_minima,
	                          vector<idx_t> required_bits);
	~PerfectAggregateHashTable() override;

public:
	//! Add the given data to the HT
	void AddChunk(DataChunk &groups, DataChunk &payload);

	//! Combines the target perfect aggregate HT into this one
	void Combine(PerfectAggregateHashTable &other);

	//! Scan the HT starting from the scan_position
	void Scan(idx_t &scan_position, DataChunk &result);

protected:
	Vector addresses;
	//! The required bits per group
	vector<idx_t> required_bits;
	//! The total required bits for the HT (this determines the max capacity)
	idx_t total_required_bits;
	//! The total amount of groups
	idx_t total_groups;
	//! The tuple size
	idx_t tuple_size;
	//! The number of grouping columns
	idx_t grouping_columns;

	// The actual pointer to the data
	data_ptr_t data;
	//! The owned data of the HT
	unique_ptr<data_t[]> owned_data;
	//! Information on whether or not a specific group has any entries
	unique_ptr<bool[]> group_is_set;

	//! The minimum values for each of the group columns
	vector<Value> group_minima;

	//! Reused selection vector
	SelectionVector sel;

private:
	//! Destroy the perfect aggregate HT (called automatically by the destructor)
	void Destroy();
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/aggregate/physical_simple_aggregate.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalSimpleAggregate is an aggregate operator that can only perform aggregates (1) without any groups, (2)
//! without any DISTINCT aggregates, and (3) when all aggregates are combineable
class PhysicalSimpleAggregate : public PhysicalOperator {
public:
	PhysicalSimpleAggregate(vector<LogicalType> types, vector<unique_ptr<Expression>> expressions,
	                        idx_t estimated_cardinality);

	//! The aggregates that have to be computed
	vector<unique_ptr<Expression>> aggregates;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	string ParamsToString() const override;

	bool IsSink() const override {
		return true;
	}

	bool ParallelSink() const override {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/thread_context.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class ClientContext;

//! The ThreadContext holds thread-local info for parallel usage
class ThreadContext {
public:
	explicit ThreadContext(ClientContext &context);

	//! The operator profiler for the individual thread context
	OperatorProfiler profiler;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/aggregate/physical_window.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalStreamingWindow implements streaming window functions (i.e. with an empty OVER clause)
class PhysicalStreamingWindow : public PhysicalOperator {
public:
	PhysicalStreamingWindow(vector<LogicalType> types, vector<unique_ptr<Expression>> select_list,
	                        idx_t estimated_cardinality,
	                        PhysicalOperatorType type = PhysicalOperatorType::STREAMING_WINDOW);

	//! The projection list of the WINDOW statement
	vector<unique_ptr<Expression>> select_list;

public:
	unique_ptr<GlobalOperatorState> GetGlobalOperatorState(ClientContext &context) const override;
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;

	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	string ParamsToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/aggregate/physical_window.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! PhysicalWindow implements window functions
//! It assumes that all functions have a common partitioning and ordering
class PhysicalWindow : public PhysicalOperator {
public:
	PhysicalWindow(vector<LogicalType> types, vector<unique_ptr<Expression>> select_list, idx_t estimated_cardinality,
	               PhysicalOperatorType type = PhysicalOperatorType::WINDOW);

	//! The projection list of the WINDOW statement (may contain aggregates)
	vector<unique_ptr<Expression>> select_list;

public:
	// Source interface
	unique_ptr<LocalSourceState> GetLocalSourceState(ExecutionContext &context,
	                                                 GlobalSourceState &gstate) const override;
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

	bool ParallelSource() const override {
		return true;
	}

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const override;

	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool IsSink() const override {
		return true;
	}

	bool ParallelSink() const override {
		return true;
	}

public:
	idx_t MaxThreads(ClientContext &context);

	string ParamsToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/window_segment_tree.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class WindowSegmentTree {
public:
	using FrameBounds = std::pair<idx_t, idx_t>;

	WindowSegmentTree(AggregateFunction &aggregate, FunctionData *bind_info, const LogicalType &result_type,
	                  ChunkCollection *input, const ValidityMask &filter_mask, WindowAggregationMode mode);
	~WindowSegmentTree();

	//! First row contains the result.
	void Compute(Vector &result, idx_t rid, idx_t start, idx_t end);

private:
	void ConstructTree();
	void ExtractFrame(idx_t begin, idx_t end);
	void WindowSegmentValue(idx_t l_idx, idx_t begin, idx_t end);
	void AggregateInit();
	void AggegateFinal(Vector &result, idx_t rid);

	//! Use the window API, if available
	inline bool UseWindowAPI() const {
		return mode < WindowAggregationMode::COMBINE;
	}
	//! Use the combine API, if available
	inline bool UseCombineAPI() const {
		return mode < WindowAggregationMode::SEPARATE;
	}

	//! The aggregate that the window function is computed over
	AggregateFunction aggregate;
	//! The bind info of the aggregate
	FunctionData *bind_info;
	//! The result type of the window function
	LogicalType result_type;

	//! Data pointer that contains a single state, used for intermediate window segment aggregation
	vector<data_t> state;
	//! Input data chunk, used for intermediate window segment aggregation
	DataChunk inputs;
	//! The filtered rows in inputs.
	SelectionVector filter_sel;
	//! A vector of pointers to "state", used for intermediate window segment aggregation
	Vector statep;
	//! The frame boundaries, used for the window functions
	FrameBounds frame;
	//! The active data in the inputs. Used for the window functions
	FrameBounds active;
	//! Reused result state container for the window functions
	Vector statev;

	//! The actual window segment tree: an array of aggregate states that represent all the intermediate nodes
	unique_ptr<data_t[]> levels_flat_native;
	//! For each level, the starting location in the levels_flat_native array
	vector<idx_t> levels_flat_start;

	//! The total number of internal nodes of the tree, stored in levels_flat_native
	idx_t internal_nodes;

	//! The (sorted) input chunk collection on which the tree is built
	ChunkCollection *input_ref;

	//! The filtered rows in input_ref.
	const ValidityMask &filter_mask;

	//! Use the window API, if available
	WindowAggregationMode mode;

	// TREE_FANOUT needs to cleanly divide STANDARD_VECTOR_SIZE
	static constexpr idx_t TREE_FANOUT = 64;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/filter/physical_filter.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalFilter represents a filter operator. It removes non-matching tuples
//! from the result. Note that it does not physically change the data, it only
//! adds a selection vector to the chunk.
class PhysicalFilter : public PhysicalOperator {
public:
	PhysicalFilter(vector<LogicalType> types, vector<unique_ptr<Expression>> select_list, idx_t estimated_cardinality);

	//! The filter expression
	unique_ptr<Expression> expression;

public:
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;

	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}
	bool RequiresCache() const override {
		return true;
	}

	string ParamsToString() const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_batch_collector.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_result_collector.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class PreparedStatementData;

//! PhysicalResultCollector is an abstract class that is used to generate the final result of a query
class PhysicalResultCollector : public PhysicalOperator {
public:
	PhysicalResultCollector(PreparedStatementData &data);

	StatementType statement_type;
	StatementProperties properties;
	PhysicalOperator *plan;
	vector<string> names;

public:
	static unique_ptr<PhysicalResultCollector> GetResultCollector(ClientContext &context, PreparedStatementData &data);

public:
	//! The final method used to fetch the query result from this operator
	virtual unique_ptr<QueryResult> GetResult(GlobalSinkState &state) = 0;

	bool IsSink() const override {
		return true;
	}

public:
	vector<PhysicalOperator *> GetChildren() const override;

	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
};

} // namespace duckdb


namespace duckdb {

class PhysicalBatchCollector : public PhysicalResultCollector {
public:
	PhysicalBatchCollector(PreparedStatementData &data);

public:
	unique_ptr<QueryResult> GetResult(GlobalSinkState &state) override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool RequiresBatchIndex() const override {
		return true;
	}

	bool ParallelSink() const override {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_execute.hpp
//
//
//===----------------------------------------------------------------------===//




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









namespace duckdb {
class CatalogEntry;
class PhysicalOperator;
class SQLStatement;

class PreparedStatementData {
public:
	DUCKDB_API explicit PreparedStatementData(StatementType type);
	DUCKDB_API ~PreparedStatementData();

	StatementType statement_type;
	//! The unbound SQL statement that was prepared
	unique_ptr<SQLStatement> unbound_statement;
	//! The fully prepared physical plan of the prepared statement
	unique_ptr<PhysicalOperator> plan;
	//! The map of parameter index to the actual value entry
	unordered_map<idx_t, vector<unique_ptr<Value>>> value_map;

	//! The result names of the transaction
	vector<string> names;
	//! The result types of the transaction
	vector<LogicalType> types;

	//! The statement properties
	StatementProperties properties;

	//! The catalog version of when the prepared statement was bound
	//! If this version is lower than the current catalog version, we have to rebind the prepared statement
	idx_t catalog_version;

public:
	//! Bind a set of values to the prepared statement data
	DUCKDB_API void Bind(vector<Value> values);
	//! Get the expected SQL Type of the bound parameter
	DUCKDB_API LogicalType GetType(idx_t param_index);
};

} // namespace duckdb


namespace duckdb {

class PhysicalExecute : public PhysicalOperator {
public:
	explicit PhysicalExecute(PhysicalOperator *plan);

	PhysicalOperator *plan;
	unique_ptr<PhysicalOperator> owned_plan;
	shared_ptr<PreparedStatementData> prepared;

public:
	vector<PhysicalOperator *> GetChildren() const override;

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_explain_analyze.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class PhysicalExplainAnalyze : public PhysicalOperator {
public:
	PhysicalExplainAnalyze(vector<LogicalType> types)
	    : PhysicalOperator(PhysicalOperatorType::EXPLAIN_ANALYZE, move(types), 1) {
	}

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink Interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool IsSink() const override {
		return true;
	}

	bool ParallelSink() const override {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_limit.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhyisicalLimit represents the LIMIT operator
class PhysicalLimit : public PhysicalOperator {
public:
	PhysicalLimit(vector<LogicalType> types, idx_t limit, idx_t offset, unique_ptr<Expression> limit_expression,
	              unique_ptr<Expression> offset_expression, idx_t estimated_cardinality);

	idx_t limit_value;
	idx_t offset_value;
	unique_ptr<Expression> limit_expression;
	unique_ptr<Expression> offset_expression;

public:
	bool IsOrderDependent() const override {
		return true;
	}

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink Interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool IsSink() const override {
		return true;
	}

	bool ParallelSink() const override {
		return true;
	}

	bool RequiresBatchIndex() const override {
		return true;
	}

public:
	static bool ComputeOffset(ExecutionContext &context, DataChunk &input, idx_t &limit, idx_t &offset,
	                          idx_t current_offset, idx_t &max_element, Expression *limit_expression,
	                          Expression *offset_expression);
	static bool HandleOffset(DataChunk &input, idx_t &current_offset, idx_t offset, idx_t limit);
	static Value GetDelimiter(ExecutionContext &context, DataChunk &input, Expression *expr);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_streaming_limit.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class PhysicalStreamingLimit : public PhysicalOperator {
public:
	PhysicalStreamingLimit(vector<LogicalType> types, idx_t limit, idx_t offset,
	                       unique_ptr<Expression> limit_expression, unique_ptr<Expression> offset_expression,
	                       idx_t estimated_cardinality, bool parallel);

	idx_t limit_value;
	idx_t offset_value;
	unique_ptr<Expression> limit_expression;
	unique_ptr<Expression> offset_expression;
	bool parallel;

public:
	// Operator interface
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	unique_ptr<GlobalOperatorState> GetGlobalOperatorState(ClientContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool IsOrderDependent() const override;
	bool ParallelOperator() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_limit_percent.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhyisicalLimitPercent represents the LIMIT PERCENT operator
class PhysicalLimitPercent : public PhysicalOperator {
public:
	PhysicalLimitPercent(vector<LogicalType> types, double limit_percent, idx_t offset,
	                     unique_ptr<Expression> limit_expression, unique_ptr<Expression> offset_expression,
	                     idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::LIMIT_PERCENT, move(types), estimated_cardinality),
	      limit_percent(limit_percent), offset_value(offset), limit_expression(move(limit_expression)),
	      offset_expression(move(offset_expression)) {
	}

	double limit_percent;
	idx_t offset_value;
	unique_ptr<Expression> limit_expression;
	unique_ptr<Expression> offset_expression;

public:
	bool IsOrderDependent() const override {
		return true;
	}

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink Interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	bool IsSink() const override {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_vacuum.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalVacuum represents an etension LOAD operation
class PhysicalLoad : public PhysicalOperator {
public:
	explicit PhysicalLoad(unique_ptr<LoadInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::LOAD, {LogicalType::BOOLEAN}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<LoadInfo> info;

public:
	// Source interface
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/extension_helper.hpp
//
//
//===----------------------------------------------------------------------===//



#include <string>


namespace duckdb {
class DuckDB;

enum class ExtensionLoadResult : uint8_t { LOADED_EXTENSION = 0, EXTENSION_UNKNOWN = 1, NOT_LOADED = 2 };

struct DefaultExtension {
	const char *name;
	const char *description;
	bool statically_loaded;
};

class ExtensionHelper {
public:
	static void LoadAllExtensions(DuckDB &db);

	static ExtensionLoadResult LoadExtension(DuckDB &db, const std::string &extension);

	static void InstallExtension(DatabaseInstance &db, const string &extension, bool force_install);
	static void LoadExternalExtension(DatabaseInstance &db, const string &extension);

	static string ExtensionDirectory(FileSystem &fs);

	static idx_t DefaultExtensionCount();
	static DefaultExtension GetDefaultExtension(idx_t index);

private:
	static const vector<string> PathComponents();

private:
	static ExtensionLoadResult LoadExtensionInternal(DuckDB &db, const std::string &extension, bool initial_load);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_materialized_collector.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class PhysicalMaterializedCollector : public PhysicalResultCollector {
public:
	PhysicalMaterializedCollector(PreparedStatementData &data, bool parallel);

	bool parallel;

public:
	unique_ptr<QueryResult> GetResult(GlobalSinkState &state) override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool ParallelSink() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_pragma.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! PhysicalPragma represents the PRAGMA operator
class PhysicalPragma : public PhysicalOperator {
public:
	PhysicalPragma(PragmaFunction function_p, PragmaInfo info_p, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::PRAGMA, {LogicalType::BOOLEAN}, estimated_cardinality),
	      function(move(function_p)), info(move(info_p)) {
	}

	//! The pragma function to call
	PragmaFunction function;
	//! The context of the call
	PragmaInfo info;

public:
	// Source interface
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_prepare.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class PhysicalPrepare : public PhysicalOperator {
public:
	PhysicalPrepare(string name, shared_ptr<PreparedStatementData> prepared, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::PREPARE, {LogicalType::BOOLEAN}, estimated_cardinality), name(name),
	      prepared(move(prepared)) {
	}

	string name;
	shared_ptr<PreparedStatementData> prepared;

public:
	// Source interface
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_reservoir_sample.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalReservoirSample represents a sample taken using reservoir sampling, which is a blocking sampling method
class PhysicalReservoirSample : public PhysicalOperator {
public:
	PhysicalReservoirSample(vector<LogicalType> types, unique_ptr<SampleOptions> options, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::RESERVOIR_SAMPLE, move(types), estimated_cardinality),
	      options(move(options)) {
	}

	unique_ptr<SampleOptions> options;

public:
	// Source interface
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool ParallelSink() const override {
		return true;
	}

	bool IsSink() const override {
		return true;
	}

	string ParamsToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/reservoir_sample.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class BaseReservoirSampling {
public:
	explicit BaseReservoirSampling(int64_t seed);
	BaseReservoirSampling();

	void InitializeReservoir(idx_t cur_size, idx_t sample_size);

	void SetNextEntry();

	void ReplaceElement();

	//! The random generator
	RandomEngine random;
	//! Priority queue of [random element, index] for each of the elements in the sample
	std::priority_queue<std::pair<double, idx_t>> reservoir_weights;
	//! The next element to sample
	idx_t next_index;
	//! The reservoir threshold of the current min entry
	double min_threshold;
	//! The reservoir index of the current min entry
	idx_t min_entry;
	//! The current count towards next index (i.e. we will replace an entry in next_index - current_count tuples)
	idx_t current_count;
};

class BlockingSample {
public:
	explicit BlockingSample(int64_t seed) : base_reservoir_sample(seed), random(base_reservoir_sample.random) {
	}
	virtual ~BlockingSample() {
	}

	//! Add a chunk of data to the sample
	virtual void AddToReservoir(DataChunk &input) = 0;

	//! Fetches a chunk from the sample. Note that this method is destructive and should only be used after the
	// sample is completely built.
	virtual unique_ptr<DataChunk> GetChunk() = 0;

protected:
	//! The reservoir sampling
	BaseReservoirSampling base_reservoir_sample;
	RandomEngine &random;
};

//! The reservoir sample class maintains a streaming sample of fixed size "sample_count"
class ReservoirSample : public BlockingSample {
public:
	ReservoirSample(Allocator &allocator, idx_t sample_count, int64_t seed);

	//! Add a chunk of data to the sample
	void AddToReservoir(DataChunk &input) override;

	//! Fetches a chunk from the sample. Note that this method is destructive and should only be used after the
	//! sample is completely built.
	unique_ptr<DataChunk> GetChunk() override;

private:
	//! Replace a single element of the input
	void ReplaceElement(DataChunk &input, idx_t index_in_chunk);

	//! Fills the reservoir up until sample_count entries, returns how many entries are still required
	idx_t FillReservoir(DataChunk &input);

private:
	//! The size of the reservoir sample
	idx_t sample_count;
	//! The current reservoir
	ChunkCollection reservoir;
};

//! The reservoir sample sample_size class maintains a streaming sample of variable size
class ReservoirSamplePercentage : public BlockingSample {
	constexpr static idx_t RESERVOIR_THRESHOLD = 100000;

public:
	ReservoirSamplePercentage(Allocator &allocator, double percentage, int64_t seed);

	//! Add a chunk of data to the sample
	void AddToReservoir(DataChunk &input) override;

	//! Fetches a chunk from the sample. Note that this method is destructive and should only be used after the
	//! sample is completely built.
	unique_ptr<DataChunk> GetChunk() override;

private:
	void Finalize();

private:
	Allocator &allocator;
	//! The sample_size to sample
	double sample_percentage;
	//! The fixed sample size of the sub-reservoirs
	idx_t reservoir_sample_size;
	//! The current sample
	unique_ptr<ReservoirSample> current_sample;
	//! The set of finished samples of the reservoir sample
	vector<unique_ptr<ReservoirSample>> finished_samples;
	//! The amount of tuples that have been processed so far
	idx_t current_count = 0;
	//! Whether or not the stream is finalized. The stream is automatically finalized on the first call to GetChunk();
	bool is_finalized;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_set.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! PhysicalSet represents a SET operation (e.g. SET a = 42)
class PhysicalSet : public PhysicalOperator {
public:
	PhysicalSet(const std::string &name_p, Value value_p, SetScope scope_p, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::SET, {LogicalType::BOOLEAN}, estimated_cardinality), name(name_p),
	      value(value_p), scope(scope_p) {
	}

public:
	// Source interface
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	const std::string name;
	const Value value;
	const SetScope scope;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_streaming_sample.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalStreamingSample represents a streaming sample using either system or bernoulli sampling
class PhysicalStreamingSample : public PhysicalOperator {
public:
	PhysicalStreamingSample(vector<LogicalType> types, SampleMethod method, double percentage, int64_t seed,
	                        idx_t estimated_cardinality);

	SampleMethod method;
	double percentage;
	int64_t seed;

public:
	// Operator interface
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	string ParamsToString() const override;

private:
	void SystemSample(DataChunk &input, DataChunk &result, OperatorState &state) const;
	void BernoulliSample(DataChunk &input, DataChunk &result, OperatorState &state) const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_transaction.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalTransaction represents a transaction operator (e.g. BEGIN or COMMIT)
class PhysicalTransaction : public PhysicalOperator {
public:
	explicit PhysicalTransaction(unique_ptr<TransactionInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::TRANSACTION, {LogicalType::BOOLEAN}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<TransactionInfo> info;

public:
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/helper/physical_vacuum.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalVacuum represents a VACUUM operation (e.g. VACUUM or ANALYZE)
class PhysicalVacuum : public PhysicalOperator {
public:
	explicit PhysicalVacuum(unique_ptr<VacuumInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::VACUUM, {LogicalType::BOOLEAN}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<VacuumInfo> info;

public:
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/perfect_hash_join_executor.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class PhysicalHashJoinState;
class HashJoinGlobalState;
class PhysicalHashJoin;

struct PerfectHashJoinStats {
	Value build_min;
	Value build_max;
	Value probe_min;
	Value probe_max;
	bool is_build_small = false;
	bool is_build_dense = false;
	bool is_probe_in_domain = false;
	idx_t build_range = 0;
	idx_t estimated_cardinality = 0;
};

//! PhysicalHashJoin represents a hash loop join between two tables
class PerfectHashJoinExecutor {
	using PerfectHashTable = std::vector<Vector>;

public:
	explicit PerfectHashJoinExecutor(const PhysicalHashJoin &join, JoinHashTable &ht, PerfectHashJoinStats pjoin_stats);

public:
	bool CanDoPerfectHashJoin();

	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context);
	OperatorResultType ProbePerfectHashTable(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                                         OperatorState &state);
	bool BuildPerfectHashTable(LogicalType &type);

private:
	void FillSelectionVectorSwitchProbe(Vector &source, SelectionVector &build_sel_vec, SelectionVector &probe_sel_vec,
	                                    idx_t count, idx_t &probe_sel_count);
	template <typename T>
	void TemplatedFillSelectionVectorProbe(Vector &source, SelectionVector &build_sel_vec,
	                                       SelectionVector &probe_sel_vec, idx_t count, idx_t &prob_sel_count);

	bool FillSelectionVectorSwitchBuild(Vector &source, SelectionVector &sel_vec, SelectionVector &seq_sel_vec,
	                                    idx_t count);
	template <typename T>
	bool TemplatedFillSelectionVectorBuild(Vector &source, SelectionVector &sel_vec, SelectionVector &seq_sel_vec,
	                                       idx_t count);
	bool FullScanHashTable(JoinHTScanState &state, LogicalType &key_type);

private:
	const PhysicalHashJoin &join;
	JoinHashTable &ht;
	//! Columnar perfect hash table
	PerfectHashTable perfect_hash_table;
	//! Build and probe statistics
	PerfectHashJoinStats perfect_join_statistics;
	//! Stores the occurences of each value in the build side
	unique_ptr<bool[]> bitmap_build_idx;
	//! Stores the number of unique keys in the build side
	idx_t unique_keys = 0;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_hash_join.hpp
//
//
//===----------------------------------------------------------------------===//







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_comparison_join.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_join.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalJoin represents the base class of the join operators
class PhysicalJoin : public PhysicalOperator {
public:
	PhysicalJoin(LogicalOperator &op, PhysicalOperatorType type, JoinType join_type, idx_t estimated_cardinality);

	JoinType join_type;

public:
	bool EmptyResultIfRHSIsEmpty() const;

	static void ConstructSemiJoinResult(DataChunk &left, DataChunk &result, bool found_match[]);
	static void ConstructAntiJoinResult(DataChunk &left, DataChunk &result, bool found_match[]);
	static void ConstructMarkJoinResult(DataChunk &join_keys, DataChunk &left, DataChunk &result, bool found_match[],
	                                    bool has_null);
	static void ConstructLeftJoinResult(DataChunk &left, DataChunk &result, bool found_match[]);

public:
	static void BuildJoinPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state,
	                               PhysicalOperator &op);
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
	vector<const PhysicalOperator *> GetSources() const override;
};

} // namespace duckdb



namespace duckdb {
class ChunkCollection;

//! PhysicalJoin represents the base class of the join operators
class PhysicalComparisonJoin : public PhysicalJoin {
public:
	PhysicalComparisonJoin(LogicalOperator &op, PhysicalOperatorType type, vector<JoinCondition> cond,
	                       JoinType join_type, idx_t estimated_cardinality);

	vector<JoinCondition> conditions;

public:
	string ParamsToString() const override;

	//! Construct the join result of a join with an empty RHS
	static void ConstructEmptyJoinResult(JoinType type, bool has_null, DataChunk &input, DataChunk &result);
	//! Construct the remainder of a Full Outer Join based on which tuples in the RHS found no match
	static void ConstructFullOuterJoinResult(bool *found_match, ChunkCollection &input, DataChunk &result,
	                                         idx_t &scan_position);
};

} // namespace duckdb




namespace duckdb {

//! PhysicalHashJoin represents a hash loop join between two tables
class PhysicalHashJoin : public PhysicalComparisonJoin {
public:
	PhysicalHashJoin(LogicalOperator &op, unique_ptr<PhysicalOperator> left, unique_ptr<PhysicalOperator> right,
	                 vector<JoinCondition> cond, JoinType join_type, const vector<idx_t> &left_projection_map,
	                 const vector<idx_t> &right_projection_map, vector<LogicalType> delim_types,
	                 idx_t estimated_cardinality, PerfectHashJoinStats perfect_join_stats);
	PhysicalHashJoin(LogicalOperator &op, unique_ptr<PhysicalOperator> left, unique_ptr<PhysicalOperator> right,
	                 vector<JoinCondition> cond, JoinType join_type, idx_t estimated_cardinality,
	                 PerfectHashJoinStats join_state);

	vector<idx_t> right_projection_map;
	//! The types of the keys
	vector<LogicalType> condition_types;
	//! The types of all conditions
	vector<LogicalType> build_types;
	//! Duplicate eliminated types; only used for delim_joins (i.e. correlated subqueries)
	vector<LogicalType> delim_types;
	// used in perfect hash join
	PerfectHashJoinStats perfect_join_statistics;

public:
	// Operator Interface
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	bool RequiresCache() const override {
		return true;
	}

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

	bool IsSource() const override {
		return IsRightOuterJoin(join_type);
	}
	bool ParallelSource() const override {
		return true;
	}

public:
	// Sink Interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_blockwise_nl_join.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalBlockwiseNLJoin represents a nested loop join between two tables on arbitrary expressions. This is different
//! from the PhysicalNestedLoopJoin in that it does not require expressions to be comparisons between the LHS and the
//! RHS.
class PhysicalBlockwiseNLJoin : public PhysicalJoin {
public:
	PhysicalBlockwiseNLJoin(LogicalOperator &op, unique_ptr<PhysicalOperator> left, unique_ptr<PhysicalOperator> right,
	                        unique_ptr<Expression> condition, JoinType join_type, idx_t estimated_cardinality);

	unique_ptr<Expression> condition;

public:
	// Operator Interface
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	bool RequiresCache() const override {
		return true;
	}

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

	bool IsSource() const override {
		return IsRightOuterJoin(join_type);
	}
	bool ParallelSource() const override {
		return true;
	}

public:
	// Sink interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

public:
	string ParamsToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_cross_product.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
//! PhysicalCrossProduct represents a cross product between two tables
class PhysicalCrossProduct : public PhysicalOperator {
public:
	PhysicalCrossProduct(vector<LogicalType> types, unique_ptr<PhysicalOperator> left,
	                     unique_ptr<PhysicalOperator> right, idx_t estimated_cardinality);

public:
	// Operator Interface
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	bool RequiresCache() const override {
		return true;
	}

public:
	// Sink Interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
	vector<const PhysicalOperator *> GetSources() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/scan/physical_chunk_scan.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! The PhysicalChunkCollectionScan scans a Chunk Collection
class PhysicalChunkScan : public PhysicalOperator {
public:
	PhysicalChunkScan(vector<LogicalType> types, PhysicalOperatorType op_type, idx_t estimated_cardinality)
	    : PhysicalOperator(op_type, move(types), estimated_cardinality), collection(nullptr) {
	}

	// the chunk collection to scan
	ChunkCollection *collection;
	//! Owned chunk collection, if any
	unique_ptr<ChunkCollection> owned_collection;

public:
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/set/physical_recursive_cte.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class Pipeline;
class RecursiveCTEState;

class PhysicalRecursiveCTE : public PhysicalOperator {
public:
	PhysicalRecursiveCTE(vector<LogicalType> types, bool union_all, unique_ptr<PhysicalOperator> top,
	                     unique_ptr<PhysicalOperator> bottom, idx_t estimated_cardinality);
	~PhysicalRecursiveCTE() override;

	bool union_all;
	std::shared_ptr<ChunkCollection> working_table;
	vector<shared_ptr<Pipeline>> pipelines;

public:
	// Source interface
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool IsSink() const override {
		return true;
	}

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;

	vector<const PhysicalOperator *> GetSources() const override;

private:
	//! Probe Hash Table and eliminate duplicate rows
	idx_t ProbeHT(DataChunk &chunk, RecursiveCTEState &state) const;

	void ExecuteRecursivePipelines(ExecutionContext &context) const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/distributive_functions.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct BitAndFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct BitOrFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct BitXorFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CountStarFun {
	static AggregateFunction GetFunction();

	static void RegisterFunction(BuiltinFunctions &set);
};

struct CountFun {
	static AggregateFunction GetFunction();

	static void RegisterFunction(BuiltinFunctions &set);
};

struct BoolAndFun {
	static AggregateFunction GetFunction();

	static void RegisterFunction(BuiltinFunctions &set);
};

struct BoolOrFun {
	static AggregateFunction GetFunction();

	static void RegisterFunction(BuiltinFunctions &set);
};

struct ProductFun {
	static AggregateFunction GetFunction();

	static void RegisterFunction(BuiltinFunctions &set);
};

struct ApproxCountDistinctFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ArgMinFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ArgMaxFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct FirstFun {
	static AggregateFunction GetFunction(const LogicalType &type);

	static void RegisterFunction(BuiltinFunctions &set);
};

struct MaxFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MinFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MaxByFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MinByFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SumFun {
	static AggregateFunction GetSumAggregate(PhysicalType type);
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SkewFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct KurtosisFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct EntropyFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StringAggFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_piecewise_merge_join.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_piecewise_merge_join.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct GlobalSortState;

//! PhysicalRangeJoin represents one or more inequality range join predicates between
//! two tables
class PhysicalRangeJoin : public PhysicalComparisonJoin {
public:
	class LocalSortedTable {
	public:
		LocalSortedTable(Allocator &allocator, const PhysicalRangeJoin &op, const idx_t child);

		void Sink(DataChunk &input, GlobalSortState &global_sort_state);

		inline void Sort(GlobalSortState &global_sort_state) {
			local_sort_state.Sort(global_sort_state, true);
		}

		//! The hosting operator
		const PhysicalRangeJoin &op;
		//! The local sort state
		LocalSortState local_sort_state;
		//! Local copy of the sorting expression executor
		ExpressionExecutor executor;
		//! Holds a vector of incoming sorting columns
		DataChunk keys;
		//! The number of NULL values
		idx_t has_null;
		//! The total number of rows
		idx_t count;

	private:
		// Merge the NULLs of all non-DISTINCT predicates into the primary so they sort to the end.
		idx_t MergeNulls(const vector<JoinCondition> &conditions);
	};

	class GlobalSortedTable {
	public:
		GlobalSortedTable(ClientContext &context, const vector<BoundOrderByNode> &orders, RowLayout &payload_layout);

		inline idx_t Count() const {
			return count;
		}

		inline idx_t BlockCount() const {
			if (global_sort_state.sorted_blocks.empty()) {
				return 0;
			}
			D_ASSERT(global_sort_state.sorted_blocks.size() == 1);
			return global_sort_state.sorted_blocks[0]->radix_sorting_data.size();
		}

		inline idx_t BlockSize(idx_t i) const {
			return global_sort_state.sorted_blocks[0]->radix_sorting_data[i].count;
		}

		void Combine(LocalSortedTable &ltable);
		void IntializeMatches();
		void Print();

		//! Starts the sorting process.
		void Finalize(Pipeline &pipeline, Event &event);
		//! Schedules tasks to merge sort the current child's data during a Finalize phase
		void ScheduleMergeTasks(Pipeline &pipeline, Event &event);

		GlobalSortState global_sort_state;
		//! Whether or not the RHS has NULL values
		atomic<idx_t> has_null;
		//! The total number of rows in the RHS
		atomic<idx_t> count;
		//! A bool indicating for each tuple in the RHS if they found a match (only used in FULL OUTER JOIN)
		unique_ptr<bool[]> found_match;
		//! Memory usage per thread
		idx_t memory_per_thread;
	};

public:
	PhysicalRangeJoin(LogicalOperator &op, PhysicalOperatorType type, unique_ptr<PhysicalOperator> left,
	                  unique_ptr<PhysicalOperator> right, vector<JoinCondition> cond, JoinType join_type,
	                  idx_t estimated_cardinality);

public:
	// Gather the result values and slice the payload columns to those values.
	static void SliceSortedPayload(DataChunk &payload, GlobalSortState &state, const idx_t block_idx,
	                               const SelectionVector &result, const idx_t result_count, const idx_t left_cols = 0);
	// Apply a tail condition to the current selection
	static idx_t SelectJoinTail(const ExpressionType &condition, Vector &left, Vector &right,
	                            const SelectionVector *sel, idx_t count, SelectionVector *true_sel);
};

} // namespace duckdb



namespace duckdb {

//! PhysicalIEJoin represents a two inequality range join between
//! two tables
class PhysicalIEJoin : public PhysicalRangeJoin {
public:
	PhysicalIEJoin(LogicalOperator &op, unique_ptr<PhysicalOperator> left, unique_ptr<PhysicalOperator> right,
	               vector<JoinCondition> cond, JoinType join_type, idx_t estimated_cardinality);

	vector<LogicalType> join_key_types;
	vector<vector<BoundOrderByNode>> lhs_orders;
	vector<vector<BoundOrderByNode>> rhs_orders;

public:
	// Operator Interface
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

public:
	// Source interface
	unique_ptr<LocalSourceState> GetLocalSourceState(ExecutionContext &context,
	                                                 GlobalSourceState &gstate) const override;
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

	bool IsSource() const override {
		return true;
	}
	bool ParallelSource() const override {
		return true;
	}

public:
	// Sink Interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;

private:
	// resolve joins that can potentially output N*M elements (INNER, LEFT, FULL)
	void ResolveComplexJoin(ExecutionContext &context, DataChunk &result, LocalSourceState &state) const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_index_join.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

//! PhysicalIndexJoin represents an index join between two tables
class PhysicalIndexJoin : public PhysicalOperator {
public:
	PhysicalIndexJoin(LogicalOperator &op, unique_ptr<PhysicalOperator> left, unique_ptr<PhysicalOperator> right,
	                  vector<JoinCondition> cond, JoinType join_type, const vector<idx_t> &left_projection_map,
	                  vector<idx_t> right_projection_map, vector<column_t> column_ids, Index *index, bool lhs_first,
	                  idx_t estimated_cardinality);

	//! Columns from RHS used in the query
	vector<column_t> column_ids;
	//! Columns to be fetched
	vector<column_t> fetch_ids;
	//! Types of fetch columns
	vector<LogicalType> fetch_types;
	//! Columns indexed by index
	unordered_set<column_t> index_ids;
	//! Projected ids from LHS
	vector<column_t> left_projection_map;
	//! Projected ids from RHS
	vector<column_t> right_projection_map;
	//! The types of the keys
	vector<LogicalType> condition_types;
	//! The types of all conditions
	vector<LogicalType> build_types;
	//! Index used for join
	Index *index;

	vector<JoinCondition> conditions;

	JoinType join_type;
	//! In case we swap rhs with lhs we need to output columns related to rhs first.
	bool lhs_first = true;

public:
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	bool RequiresCache() const override {
		return true;
	}

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
	vector<const PhysicalOperator *> GetSources() const override;

private:
	void GetRHSMatches(ExecutionContext &context, DataChunk &input, OperatorState &state_p) const;
	//! Fills result chunk
	void Output(ExecutionContext &context, DataChunk &input, DataChunk &chunk, OperatorState &state_p) const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/scan/physical_table_scan.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

//! Represents a scan of a base table
class PhysicalTableScan : public PhysicalOperator {
public:
	PhysicalTableScan(vector<LogicalType> types, TableFunction function, unique_ptr<FunctionData> bind_data,
	                  vector<column_t> column_ids, vector<string> names, unique_ptr<TableFilterSet> table_filters,
	                  idx_t estimated_cardinality);

	//! The table function
	TableFunction function;
	//! Bind data of the function
	unique_ptr<FunctionData> bind_data;
	//! The projected-out column ids
	vector<column_t> column_ids;
	//! The names of the columns
	vector<string> names;
	//! The table filters
	unique_ptr<TableFilterSet> table_filters;

public:
	string GetName() const override;
	string ParamsToString() const override;

	bool Equals(const PhysicalOperator &other) const override;

public:
	unique_ptr<LocalSourceState> GetLocalSourceState(ExecutionContext &context,
	                                                 GlobalSourceState &gstate) const override;
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
	idx_t GetBatchIndex(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	                    LocalSourceState &lstate) const override;

	bool ParallelSource() const override {
		return true;
	}

	bool SupportsBatchIndex() const override {
		return function.get_batch_index != nullptr;
	}

	double GetProgress(ClientContext &context, GlobalSourceState &gstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table/table_scan.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class TableCatalogEntry;

struct TableScanBindData : public TableFunctionData {
	explicit TableScanBindData(TableCatalogEntry *table) : table(table), is_index_scan(false), chunk_count(0) {
	}

	//! The table to scan
	TableCatalogEntry *table;

	//! Whether or not the table scan is an index scan
	bool is_index_scan;
	//! The row ids to fetch (in case of an index scan)
	vector<row_t> result_ids;

	//! How many chunks we already scanned
	atomic<idx_t> chunk_count;

public:
	bool Equals(const FunctionData &other_p) const override {
		auto &other = (const TableScanBindData &)other_p;
		return other.table == table && result_ids == other.result_ids;
	}
};

//! The table scan function represents a sequential scan over one of DuckDB's base tables.
struct TableScanFunction {
	static TableFunction GetFunction();
	static TableCatalogEntry *GetTableEntry(const TableFunction &function, const FunctionData *bind_data);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_nested_loop_join.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
idx_t nested_loop_join(ExpressionType op, Vector &left, Vector &right, idx_t &lpos, idx_t &rpos, sel_t lvector[],
                       sel_t rvector[]);
idx_t nested_loop_comparison(ExpressionType op, Vector &left, Vector &right, sel_t lvector[], sel_t rvector[],
                             idx_t count);

//! PhysicalNestedLoopJoin represents a nested loop join between two tables
class PhysicalNestedLoopJoin : public PhysicalComparisonJoin {
public:
	PhysicalNestedLoopJoin(LogicalOperator &op, unique_ptr<PhysicalOperator> left, unique_ptr<PhysicalOperator> right,
	                       vector<JoinCondition> cond, JoinType join_type, idx_t estimated_cardinality);

public:
	// Operator Interface
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	bool RequiresCache() const override {
		return true;
	}

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

	bool IsSource() const override {
		return IsRightOuterJoin(join_type);
	}
	bool ParallelSource() const override {
		return true;
	}

public:
	// Sink Interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

	static bool IsSupported(const vector<JoinCondition> &conditions);

private:
	// resolve joins that output max N elements (SEMI, ANTI, MARK)
	void ResolveSimpleJoin(ExecutionContext &context, DataChunk &input, DataChunk &chunk, OperatorState &state) const;
	// resolve joins that can potentially output N*M elements (INNER, LEFT, FULL)
	OperatorResultType ResolveComplexJoin(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                                      OperatorState &state) const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/join/physical_piecewise_merge_join.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class MergeJoinGlobalState;

//! PhysicalPiecewiseMergeJoin represents a piecewise merge loop join between
//! two tables
class PhysicalPiecewiseMergeJoin : public PhysicalRangeJoin {
public:
	PhysicalPiecewiseMergeJoin(LogicalOperator &op, unique_ptr<PhysicalOperator> left,
	                           unique_ptr<PhysicalOperator> right, vector<JoinCondition> cond, JoinType join_type,
	                           idx_t estimated_cardinality);

	vector<LogicalType> join_key_types;
	vector<BoundOrderByNode> lhs_orders;
	vector<BoundOrderByNode> rhs_orders;

public:
	// Operator Interface
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	bool RequiresCache() const override {
		return true;
	}

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

	bool IsSource() const override {
		return IsRightOuterJoin(join_type);
	}
	bool ParallelSource() const override {
		return true;
	}

public:
	// Sink Interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

private:
	// resolve joins that output max N elements (SEMI, ANTI, MARK)
	void ResolveSimpleJoin(ExecutionContext &context, DataChunk &input, DataChunk &chunk, OperatorState &state) const;
	// resolve joins that can potentially output N*M elements (INNER, LEFT, FULL)
	OperatorResultType ResolveComplexJoin(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                                      OperatorState &state) const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/order/physical_order.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class OrderGlobalState;

//! Physically re-orders the input data
class PhysicalOrder : public PhysicalOperator {
public:
	PhysicalOrder(vector<LogicalType> types, vector<BoundOrderByNode> orders, idx_t estimated_cardinality);

	//! Input data
	vector<BoundOrderByNode> orders;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &gstate_p, LocalSinkState &lstate_p,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate_p, LocalSinkState &lstate_p) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

	string ParamsToString() const override;

	//! Schedules tasks to merge the data during the Finalize phase
	static void ScheduleMergeTasks(Pipeline &pipeline, Event &event, OrderGlobalState &state);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/order/physical_top_n.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! Represents a physical ordering of the data. Note that this will not change
//! the data but only add a selection vector.
class PhysicalTopN : public PhysicalOperator {
public:
	PhysicalTopN(vector<LogicalType> types, vector<BoundOrderByNode> orders, idx_t limit, idx_t offset,
	             idx_t estimated_cardinality);

	vector<BoundOrderByNode> orders;
	idx_t limit;
	idx_t offset;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}

	string ParamsToString() const override;

private:
	unique_ptr<idx_t[]> ComputeTopN(ChunkCollection &big_data, idx_t &heap_size);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/persistent/physical_copy_to_file.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! Copy the contents of a query into a table
class PhysicalCopyToFile : public PhysicalOperator {
public:
	PhysicalCopyToFile(vector<LogicalType> types, CopyFunction function, unique_ptr<FunctionData> bind_data,
	                   idx_t estimated_cardinality);

	CopyFunction function;
	unique_ptr<FunctionData> bind_data;
	string file_path;
	bool use_tmp_file;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;
	SinkFinalizeType Finalize(Pipeline &pipeline, Event &event, ClientContext &context,
	                          GlobalSinkState &gstate) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	bool IsSink() const override {
		return true;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/persistent/physical_delete.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class DataTable;

//! Physically delete data from a table
class PhysicalDelete : public PhysicalOperator {
public:
	PhysicalDelete(vector<LogicalType> types, TableCatalogEntry &tableref, DataTable &table, idx_t row_id_index,
	               idx_t estimated_cardinality, bool return_chunk)
	    : PhysicalOperator(PhysicalOperatorType::DELETE_OPERATOR, move(types), estimated_cardinality),
	      tableref(tableref), table(table), row_id_index(row_id_index), return_chunk(return_chunk) {
	}

	TableCatalogEntry &tableref;
	DataTable &table;
	idx_t row_id_index;
	bool return_chunk;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/persistent/physical_export.hpp
//
//
//===----------------------------------------------------------------------===//



#include <utility>






namespace duckdb {
//! Parse a file from disk using a specified copy function and return the set of chunks retrieved from the file
class PhysicalExport : public PhysicalOperator {
public:
	PhysicalExport(vector<LogicalType> types, CopyFunction function, unique_ptr<CopyInfo> info,
	               idx_t estimated_cardinality, BoundExportData exported_tables)
	    : PhysicalOperator(PhysicalOperatorType::EXPORT, move(types), estimated_cardinality),
	      function(std::move(function)), info(move(info)), exported_tables(move(exported_tables)) {
	}

	//! The copy function to use to read the file
	CopyFunction function;
	//! The binding info containing the set of options for reading the file
	unique_ptr<CopyInfo> info;
	//! The table info for each table that will be exported
	BoundExportData exported_tables;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	bool ParallelSink() const override {
		return true;
	}
	bool IsSink() const override {
		return true;
	}

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
	vector<const PhysicalOperator *> GetSources() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/persistent/physical_insert.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Physically insert a set of data into a table
class PhysicalInsert : public PhysicalOperator {
public:
	PhysicalInsert(vector<LogicalType> types, TableCatalogEntry *table, vector<idx_t> column_index_map,
	               vector<unique_ptr<Expression>> bound_defaults, idx_t estimated_cardinality, bool return_chunk);

	//! The map from insert column index to table column index
	vector<idx_t> column_index_map;
	//! The table to insert into
	TableCatalogEntry *table;
	//! The default expressions of the columns for which no value is provided
	vector<unique_ptr<Expression>> bound_defaults;
	//! If the returning statement is present, return the whole chunk
	bool return_chunk;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	bool IsSink() const override {
		return true;
	}

	bool ParallelSink() const override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/persistent/physical_update.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class DataTable;

//! Physically update data in a table
class PhysicalUpdate : public PhysicalOperator {
public:
	PhysicalUpdate(vector<LogicalType> types, TableCatalogEntry &tableref, DataTable &table, vector<column_t> columns,
	               vector<unique_ptr<Expression>> expressions, vector<unique_ptr<Expression>> bound_defaults,
	               idx_t estimated_cardinality, bool return_chunk)
	    : PhysicalOperator(PhysicalOperatorType::UPDATE, move(types), estimated_cardinality), tableref(tableref),
	      table(table), columns(std::move(columns)), expressions(move(expressions)),
	      bound_defaults(move(bound_defaults)), return_chunk(return_chunk) {
	}

	TableCatalogEntry &tableref;
	DataTable &table;
	vector<column_t> columns;
	vector<unique_ptr<Expression>> expressions;
	vector<unique_ptr<Expression>> bound_defaults;
	bool update_is_del_and_insert;
	//! If the returning statement is present, return the whole chunk
	bool return_chunk;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	// Sink interface
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;
	unique_ptr<LocalSinkState> GetLocalSinkState(ExecutionContext &context) const override;
	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;
	void Combine(ExecutionContext &context, GlobalSinkState &gstate, LocalSinkState &lstate) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/projection/physical_projection.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class PhysicalProjection : public PhysicalOperator {
public:
	PhysicalProjection(vector<LogicalType> types, vector<unique_ptr<Expression>> select_list,
	                   idx_t estimated_cardinality);

	vector<unique_ptr<Expression>> select_list;

public:
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

	string ParamsToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/projection/physical_unnest.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! PhysicalWindow implements window functions
class PhysicalTableInOutFunction : public PhysicalOperator {
public:
	PhysicalTableInOutFunction(vector<LogicalType> types, TableFunction function_p,
	                           unique_ptr<FunctionData> bind_data_p, vector<column_t> column_ids_p,
	                           idx_t estimated_cardinality);

public:
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	unique_ptr<GlobalOperatorState> GetGlobalOperatorState(ClientContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

private:
	//! The table function
	TableFunction function;
	//! Bind data of the function
	unique_ptr<FunctionData> bind_data;

	vector<column_t> column_ids;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/projection/physical_unnest.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! PhysicalWindow implements window functions
class PhysicalUnnest : public PhysicalOperator {
public:
	PhysicalUnnest(vector<LogicalType> types, vector<unique_ptr<Expression>> select_list, idx_t estimated_cardinality,
	               PhysicalOperatorType type = PhysicalOperatorType::UNNEST);

	//! The projection list of the UNNEST
	vector<unique_ptr<Expression>> select_list;

public:
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

public:
	static unique_ptr<OperatorState> GetState(ExecutionContext &context,
	                                          const vector<unique_ptr<Expression>> &select_list);
	static OperatorResultType ExecuteInternal(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                                          OperatorState &state, const vector<unique_ptr<Expression>> &select_list,
	                                          bool include_input = true);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/scan/physical_dummy_scan.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class PhysicalDummyScan : public PhysicalOperator {
public:
	explicit PhysicalDummyScan(vector<LogicalType> types, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::DUMMY_SCAN, move(types), estimated_cardinality) {
	}

public:
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/scan/physical_empty_result.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class PhysicalEmptyResult : public PhysicalOperator {
public:
	explicit PhysicalEmptyResult(vector<LogicalType> types, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::EMPTY_RESULT, move(types), estimated_cardinality) {
	}

public:
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/scan/physical_expression_scan.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! The PhysicalExpressionScan scans a set of expressions
class PhysicalExpressionScan : public PhysicalOperator {
public:
	PhysicalExpressionScan(vector<LogicalType> types, vector<vector<unique_ptr<Expression>>> expressions,
	                       idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::EXPRESSION_SCAN, move(types), estimated_cardinality),
	      expressions(move(expressions)) {
	}

	//! The set of expressions to scan
	vector<vector<unique_ptr<Expression>>> expressions;

public:
	unique_ptr<OperatorState> GetOperatorState(ExecutionContext &context) const override;
	OperatorResultType Execute(ExecutionContext &context, DataChunk &input, DataChunk &chunk,
	                           GlobalOperatorState &gstate, OperatorState &state) const override;

	bool ParallelOperator() const override {
		return true;
	}

public:
	bool IsFoldable() const;
	void EvaluateExpression(Allocator &allocator, idx_t expression_idx, DataChunk *child_chunk,
	                        DataChunk &result) const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_alter.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalAlter represents an ALTER TABLE command
class PhysicalAlter : public PhysicalOperator {
public:
	explicit PhysicalAlter(unique_ptr<AlterInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::ALTER, {LogicalType::BOOLEAN}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<AlterInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_function.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalCreateFunction represents a CREATE FUNCTION command
class PhysicalCreateFunction : public PhysicalOperator {
public:
	explicit PhysicalCreateFunction(unique_ptr<CreateMacroInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::CREATE_MACRO, {LogicalType::BIGINT}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<CreateMacroInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_index.hpp
//
//
//===----------------------------------------------------------------------===//









#include <fstream>

namespace duckdb {

//! Physically CREATE INDEX statement
class PhysicalCreateIndex : public PhysicalOperator {
public:
	PhysicalCreateIndex(LogicalOperator &op, TableCatalogEntry &table, vector<column_t> column_ids,
	                    vector<unique_ptr<Expression>> expressions, unique_ptr<CreateIndexInfo> info,
	                    vector<unique_ptr<Expression>> unbinded_expressions, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::CREATE_INDEX, op.types, estimated_cardinality), table(table),
	      column_ids(column_ids), expressions(move(expressions)), info(std::move(info)),
	      unbound_expressions(move(unbinded_expressions)) {
	}

	//! The table to create the index for
	TableCatalogEntry &table;
	//! The list of column IDs required for the index
	vector<column_t> column_ids;
	//! Set of expressions to index by
	vector<unique_ptr<Expression>> expressions;
	//! Info for index creation
	unique_ptr<CreateIndexInfo> info;
	//! Unbinded expressions to be used in the optimizer
	vector<unique_ptr<Expression>> unbound_expressions;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_schema.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalCreateSchema represents a CREATE SCHEMA command
class PhysicalCreateSchema : public PhysicalOperator {
public:
	explicit PhysicalCreateSchema(unique_ptr<CreateSchemaInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::CREATE_SCHEMA, {LogicalType::BIGINT}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<CreateSchemaInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_sequence.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalCreateSequence represents a CREATE SEQUENCE command
class PhysicalCreateSequence : public PhysicalOperator {
public:
	explicit PhysicalCreateSequence(unique_ptr<CreateSequenceInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::CREATE_SEQUENCE, {LogicalType::BIGINT}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<CreateSequenceInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_table.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Physically CREATE TABLE statement
class PhysicalCreateTable : public PhysicalOperator {
public:
	PhysicalCreateTable(LogicalOperator &op, SchemaCatalogEntry *schema, unique_ptr<BoundCreateTableInfo> info,
	                    idx_t estimated_cardinality);

	//! Schema to insert to
	SchemaCatalogEntry *schema;
	//! Table name to create
	unique_ptr<BoundCreateTableInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_table_as.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Physically CREATE TABLE AS statement
class PhysicalCreateTableAs : public PhysicalOperator {
public:
	PhysicalCreateTableAs(LogicalOperator &op, SchemaCatalogEntry *schema, unique_ptr<BoundCreateTableInfo> info,
	                      idx_t estimated_cardinality);

	//! Schema to insert to
	SchemaCatalogEntry *schema;
	//! Table name to create
	unique_ptr<BoundCreateTableInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;

public:
	unique_ptr<GlobalSinkState> GetGlobalSinkState(ClientContext &context) const override;

	SinkResultType Sink(ExecutionContext &context, GlobalSinkState &state, LocalSinkState &lstate,
	                    DataChunk &input) const override;

	bool IsSink() const override {
		return true;
	}
	bool ParallelSink() const override {
		return true;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_type.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalCreateType represents a CREATE TYPE command
class PhysicalCreateType : public PhysicalOperator {
public:
	explicit PhysicalCreateType(unique_ptr<CreateTypeInfo> info, idx_t estimated_cardinality);

	unique_ptr<CreateTypeInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_create_view.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalCreateView represents a CREATE VIEW command
class PhysicalCreateView : public PhysicalOperator {
public:
	explicit PhysicalCreateView(unique_ptr<CreateViewInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::CREATE_VIEW, {LogicalType::BIGINT}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<CreateViewInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/schema/physical_drop.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! PhysicalDrop represents a DROP [...] command
class PhysicalDrop : public PhysicalOperator {
public:
	explicit PhysicalDrop(unique_ptr<DropInfo> info, idx_t estimated_cardinality)
	    : PhysicalOperator(PhysicalOperatorType::DROP, {LogicalType::BOOLEAN}, estimated_cardinality),
	      info(move(info)) {
	}

	unique_ptr<DropInfo> info;

public:
	// Source interface
	unique_ptr<GlobalSourceState> GetGlobalSourceState(ClientContext &context) const override;
	void GetData(ExecutionContext &context, DataChunk &chunk, GlobalSourceState &gstate,
	             LocalSourceState &lstate) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/operator/set/physical_union.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class PhysicalUnion : public PhysicalOperator {
public:
	PhysicalUnion(vector<LogicalType> types, unique_ptr<PhysicalOperator> top, unique_ptr<PhysicalOperator> bottom,
	              idx_t estimated_cardinality);

public:
	void BuildPipelines(Executor &executor, Pipeline &current, PipelineBuildState &state) override;
	vector<const PhysicalOperator *> GetSources() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/execution/physical_plan_generator.hpp
//
//
//===----------------------------------------------------------------------===//







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_limit_percent.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalLimitPercent represents a LIMIT PERCENT clause
class LogicalLimitPercent : public LogicalOperator {
public:
	LogicalLimitPercent(double limit_percent, int64_t offset_val, unique_ptr<Expression> limit,
	                    unique_ptr<Expression> offset)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_LIMIT_PERCENT), limit_percent(limit_percent),
	      offset_val(offset_val), limit(move(limit)), offset(move(offset)) {
	}

	//! Limit percent and offset values in case they are constants, used in optimizations.
	double limit_percent;
	int64_t offset_val;
	//! The maximum amount of elements to emit
	unique_ptr<Expression> limit;
	//! The offset from the start to begin emitting elements
	unique_ptr<Expression> offset;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return children[0]->GetColumnBindings();
	}

protected:
	void ResolveTypes() override {
		types = children[0]->types;
	}
};
} // namespace duckdb





namespace duckdb {
class ClientContext;

//! The physical plan generator generates a physical execution plan from a
//! logical query plan
class PhysicalPlanGenerator {
public:
	explicit PhysicalPlanGenerator(ClientContext &context) : context(context) {
	}

	unordered_set<CatalogEntry *> dependencies;
	//! Recursive CTEs require at least one ChunkScan, referencing the working_table.
	//! This data structure is used to establish it.
	unordered_map<idx_t, std::shared_ptr<ChunkCollection>> rec_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);

protected:
	unique_ptr<PhysicalOperator> CreatePlan(LogicalOperator &op);

	unique_ptr<PhysicalOperator> CreatePlan(LogicalAggregate &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalAnyJoin &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalChunkGet &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalComparisonJoin &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCreate &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCreateTable &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCreateIndex &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCrossProduct &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalDelete &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalDelimGet &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalDelimJoin &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(LogicalLimitPercent &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalOrder &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalTopN &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(LogicalShow &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalSimple &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalUnnest &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalRecursiveCTE &op);
	unique_ptr<PhysicalOperator> CreatePlan(LogicalCTERef &op);

	unique_ptr<PhysicalOperator> CreateDistinctOn(unique_ptr<PhysicalOperator> child,
	                                              vector<unique_ptr<Expression>> distinct_targets);

	unique_ptr<PhysicalOperator> ExtractAggregateExpressions(unique_ptr<PhysicalOperator> child,
	                                                         vector<unique_ptr<Expression>> &expressions,
	                                                         vector<unique_ptr<Expression>> &groups);

private:
	ClientContext &context;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_aggregate.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

//! LogicalAggregate represents an aggregate operation with (optional) GROUP BY
//! operator.
class LogicalAggregate : public LogicalOperator {
public:
	LogicalAggregate(idx_t group_index, idx_t aggregate_index, vector<unique_ptr<Expression>> select_list);

	//! The table index for the groups of the LogicalAggregate
	idx_t group_index;
	//! The table index for the aggregates of the LogicalAggregate
	idx_t aggregate_index;
	//! The table index for the GROUPING function calls of the LogicalAggregate
	idx_t groupings_index;
	//! The set of groups (optional).
	vector<unique_ptr<Expression>> groups;
	//! The set of grouping sets (optional).
	vector<GroupingSet> grouping_sets;
	//! The list of grouping function calls (optional)
	vector<vector<idx_t>> grouping_functions;
	//! Group statistics (optional)
	vector<unique_ptr<BaseStatistics>> group_stats;

public:
	string ParamsToString() const override;

	vector<ColumnBinding> GetColumnBindings() override;

protected:
	void ResolveTypes() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_any_join.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! LogicalAnyJoin represents a join with an arbitrary expression as JoinCondition
class LogicalAnyJoin : public LogicalJoin {
public:
	explicit LogicalAnyJoin(JoinType type);

	//! The JoinCondition on which this join is performed
	unique_ptr<Expression> condition;

public:
	string ParamsToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_chunk_get.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! LogicalChunkGet represents a scan operation from a ChunkCollection
class LogicalChunkGet : public LogicalOperator {
public:
	LogicalChunkGet(idx_t table_index, vector<LogicalType> types, unique_ptr<ChunkCollection> collection)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_CHUNK_GET), table_index(table_index),
	      collection(move(collection)) {
		D_ASSERT(types.size() > 0);
		chunk_types = types;
	}

	//! The table index in the current bind context
	idx_t table_index;
	//! The types of the chunk
	vector<LogicalType> chunk_types;
	//! The chunk collection to scan
	unique_ptr<ChunkCollection> collection;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return GenerateColumnBindings(table_index, chunk_types.size());
	}

protected:
	void ResolveTypes() override {
		// types are resolved in the constructor
		this->types = chunk_types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_iterator.hpp
//
//
//===----------------------------------------------------------------------===//






#include <functional>

namespace duckdb {
class BoundQueryNode;
class BoundTableRef;

class ExpressionIterator {
public:
	static void EnumerateChildren(const Expression &expression,
	                              const std::function<void(const Expression &child)> &callback);
	static void EnumerateChildren(Expression &expression, const std::function<void(Expression &child)> &callback);
	static void EnumerateChildren(Expression &expression,
	                              const std::function<void(unique_ptr<Expression> &child)> &callback);

	static void EnumerateExpression(unique_ptr<Expression> &expr,
	                                const std::function<void(Expression &child)> &callback);

	static void EnumerateTableRefChildren(BoundTableRef &ref, const std::function<void(Expression &child)> &callback);
	static void EnumerateQueryNodeChildren(BoundQueryNode &node,
	                                       const std::function<void(Expression &child)> &callback);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_copy_to_file.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class LogicalCopyToFile : public LogicalOperator {
public:
	LogicalCopyToFile(CopyFunction function, unique_ptr<FunctionData> bind_data)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_COPY_TO_FILE), function(function), bind_data(move(bind_data)) {
	}
	CopyFunction function;
	unique_ptr<FunctionData> bind_data;
	std::string file_path;
	bool use_tmp_file;
	bool is_file_and_exists;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BIGINT);
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_create.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! LogicalCreate represents a CREATE operator
class LogicalCreate : public LogicalOperator {
public:
	LogicalCreate(LogicalOperatorType type, unique_ptr<CreateInfo> info, SchemaCatalogEntry *schema = nullptr)
	    : LogicalOperator(type), schema(schema), info(move(info)) {
	}

	SchemaCatalogEntry *schema;
	unique_ptr<CreateInfo> info;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BIGINT);
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_create_table.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class LogicalCreateTable : public LogicalOperator {
public:
	LogicalCreateTable(SchemaCatalogEntry *schema, unique_ptr<BoundCreateTableInfo> info)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_CREATE_TABLE), schema(schema), info(move(info)) {
	}

	//! Schema to insert to
	SchemaCatalogEntry *schema;
	//! Create Table information
	unique_ptr<BoundCreateTableInfo> info;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BIGINT);
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_cross_product.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalCrossProduct represents a cross product between two relations
class LogicalCrossProduct : public LogicalOperator {
public:
	LogicalCrossProduct();

public:
	vector<ColumnBinding> GetColumnBindings() override;

protected:
	void ResolveTypes() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_delete.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class LogicalDelete : public LogicalOperator {
public:
	explicit LogicalDelete(TableCatalogEntry *table)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_DELETE), table(table), table_index(0), return_chunk(false) {
	}

	TableCatalogEntry *table;
	idx_t table_index;
	bool return_chunk;

protected:
	vector<ColumnBinding> GetColumnBindings() override {
		if (return_chunk) {
			return GenerateColumnBindings(table_index, table->columns.size());
		}
		return {ColumnBinding(0, 0)};
	}

	void ResolveTypes() override {
		if (return_chunk) {
			types = table->GetTypes();
		} else {
			types.emplace_back(LogicalType::BIGINT);
		}
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_delim_get.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalDelimGet represents a duplicate eliminated scan belonging to a DelimJoin
class LogicalDelimGet : public LogicalOperator {
public:
	LogicalDelimGet(idx_t table_index, vector<LogicalType> types)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_DELIM_GET), table_index(table_index) {
		D_ASSERT(types.size() > 0);
		chunk_types = types;
	}

	//! The table index in the current bind context
	idx_t table_index;
	//! The types of the chunk
	vector<LogicalType> chunk_types;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return GenerateColumnBindings(table_index, chunk_types.size());
	}

protected:
	void ResolveTypes() override {
		// types are resolved in the constructor
		this->types = chunk_types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_distinct.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalDistinct filters duplicate entries from its child operator
class LogicalDistinct : public LogicalOperator {
public:
	LogicalDistinct() : LogicalOperator(LogicalOperatorType::LOGICAL_DISTINCT) {
	}
	explicit LogicalDistinct(vector<unique_ptr<Expression>> targets)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_DISTINCT), distinct_targets(move(targets)) {
	}
	//! The set of distinct targets (optional).
	vector<unique_ptr<Expression>> distinct_targets;

public:
	string ParamsToString() const override;

	vector<ColumnBinding> GetColumnBindings() override {
		return children[0]->GetColumnBindings();
	}

protected:
	void ResolveTypes() override {
		types = children[0]->types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_dummy_scan.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalDummyScan represents a dummy scan returning a single row
class LogicalDummyScan : public LogicalOperator {
public:
	explicit LogicalDummyScan(idx_t table_index)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_DUMMY_SCAN), table_index(table_index) {
	}

	idx_t table_index;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return {ColumnBinding(table_index, 0)};
	}

	idx_t EstimateCardinality(ClientContext &context) override {
		return 1;
	}

protected:
	void ResolveTypes() override {
		if (types.size() == 0) {
			types.emplace_back(LogicalType::INTEGER);
		}
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_empty_result.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalEmptyResult returns an empty result. This is created by the optimizer if it can reason that ceratin parts of
//! the tree will always return an empty result.
class LogicalEmptyResult : public LogicalOperator {
public:
	explicit LogicalEmptyResult(unique_ptr<LogicalOperator> op);

	//! The set of return types of the empty result
	vector<LogicalType> return_types;
	//! The columns that would be bound at this location (if the subtree was not optimized away)
	vector<ColumnBinding> bindings;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return bindings;
	}

protected:
	void ResolveTypes() override {
		this->types = return_types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_execute.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class LogicalExecute : public LogicalOperator {
public:
	explicit LogicalExecute(shared_ptr<PreparedStatementData> prepared_p)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_EXECUTE), prepared(move(prepared_p)) {
		D_ASSERT(prepared);
		types = prepared->types;
	}

	shared_ptr<PreparedStatementData> prepared;

protected:
	void ResolveTypes() override {
		// already resolved
	}
	vector<ColumnBinding> GetColumnBindings() override {
		vector<ColumnBinding> bindings;
		for (idx_t i = 0; i < types.size(); i++) {
			bindings.push_back(ColumnBinding(0, i));
		}
		return bindings;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_explain.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/explain_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

enum class ExplainType : uint8_t { EXPLAIN_STANDARD, EXPLAIN_ANALYZE };

class ExplainStatement : public SQLStatement {
public:
	explicit ExplainStatement(unique_ptr<SQLStatement> stmt, ExplainType explain_type = ExplainType::EXPLAIN_STANDARD);

	unique_ptr<SQLStatement> stmt;
	ExplainType explain_type;

protected:
	ExplainStatement(const ExplainStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb


namespace duckdb {

class LogicalExplain : public LogicalOperator {
public:
	LogicalExplain(unique_ptr<LogicalOperator> plan, ExplainType explain_type)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_EXPLAIN), explain_type(explain_type) {
		children.push_back(move(plan));
	}

	ExplainType explain_type;
	string physical_plan;
	string logical_plan_unopt;
	string logical_plan_opt;

protected:
	void ResolveTypes() override {
		types = {LogicalType::VARCHAR, LogicalType::VARCHAR};
	}
	vector<ColumnBinding> GetColumnBindings() override {
		return {ColumnBinding(0, 0), ColumnBinding(0, 1)};
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_export.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class LogicalExport : public LogicalOperator {
public:
	LogicalExport(CopyFunction function, unique_ptr<CopyInfo> copy_info, BoundExportData exported_tables)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_EXPORT), function(function), copy_info(move(copy_info)),
	      exported_tables(move(exported_tables)) {
	}
	CopyFunction function;
	unique_ptr<CopyInfo> copy_info;
	BoundExportData exported_tables;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BOOLEAN);
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_expression_get.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalExpressionGet represents a scan operation over a set of to-be-executed expressions
class LogicalExpressionGet : public LogicalOperator {
public:
	LogicalExpressionGet(idx_t table_index, vector<LogicalType> types,
	                     vector<vector<unique_ptr<Expression>>> expressions)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_EXPRESSION_GET), table_index(table_index), expr_types(types),
	      expressions(move(expressions)) {
	}

	//! The table index in the current bind context
	idx_t table_index;
	//! The types of the expressions
	vector<LogicalType> expr_types;
	//! The set of expressions
	vector<vector<unique_ptr<Expression>>> expressions;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return GenerateColumnBindings(table_index, expr_types.size());
	}

protected:
	void ResolveTypes() override {
		// types are resolved in the constructor
		this->types = expr_types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/matcher/expression_matcher.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/matcher/expression_type_matcher.hpp
//
//
//===----------------------------------------------------------------------===//







#include <algorithm>

namespace duckdb {

//! The ExpressionTypeMatcher class contains a set of matchers that can be used to pattern match ExpressionTypes
class ExpressionTypeMatcher {
public:
	virtual ~ExpressionTypeMatcher() {
	}

	virtual bool Match(ExpressionType type) = 0;
};

//! The SpecificExpressionTypeMatcher class matches a single specified Expression type
class SpecificExpressionTypeMatcher : public ExpressionTypeMatcher {
public:
	explicit SpecificExpressionTypeMatcher(ExpressionType type) : type(type) {
	}

	bool Match(ExpressionType type) override {
		return type == this->type;
	}

private:
	ExpressionType type;
};

//! The ManyExpressionTypeMatcher class matches a set of ExpressionTypes
class ManyExpressionTypeMatcher : public ExpressionTypeMatcher {
public:
	explicit ManyExpressionTypeMatcher(vector<ExpressionType> types) : types(move(types)) {
	}

	bool Match(ExpressionType type) override {
		return std::find(types.begin(), types.end(), type) != types.end();
	}

private:
	vector<ExpressionType> types;
};

//! The ComparisonExpressionTypeMatcher class matches a comparison expression
class ComparisonExpressionTypeMatcher : public ExpressionTypeMatcher {
public:
	bool Match(ExpressionType type) override {
		return type == ExpressionType::COMPARE_EQUAL || type == ExpressionType::COMPARE_GREATERTHANOREQUALTO ||
		       type == ExpressionType::COMPARE_LESSTHANOREQUALTO || type == ExpressionType::COMPARE_LESSTHAN ||
		       type == ExpressionType::COMPARE_GREATERTHAN;
	}
};
} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/matcher/set_matcher.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class SetMatcher {
public:
	//! The policy used by the SetMatcher
	enum class Policy {
		//! All entries have to be matched, and the matches have to be ordered
		ORDERED,
		//! All entries have to be matched, but the order of the matches does not matter
		UNORDERED,
		//! Only some entries have to be matched, the order of the matches does not matter
		SOME,
		//! Not initialized
		INVALID
	};

	/* The double {{}} in the intializer for excluded_entries is intentional, workaround for bug in gcc-4.9 */
	template <class T, class MATCHER>
	static bool MatchRecursive(vector<unique_ptr<MATCHER>> &matchers, vector<T *> &entries, vector<T *> &bindings,
	                           unordered_set<idx_t> excluded_entries, idx_t m_idx = 0) {
		if (m_idx == matchers.size()) {
			// matched all matchers!
			return true;
		}
		// try to find a match for the current matcher (m_idx)
		idx_t previous_binding_count = bindings.size();
		for (idx_t e_idx = 0; e_idx < entries.size(); e_idx++) {
			// first check if this entry has already been matched
			if (excluded_entries.find(e_idx) != excluded_entries.end()) {
				// it has been matched: skip this entry
				continue;
			}
			// otherwise check if the current matcher matches this entry
			if (matchers[m_idx]->Match(entries[e_idx], bindings)) {
				// m_idx matches e_idx!
				// check if we can find a complete match for this path
				// first add e_idx to the new set of excluded entries
				unordered_set<idx_t> new_excluded_entries;
				new_excluded_entries = excluded_entries;
				new_excluded_entries.insert(e_idx);
				// then match the next matcher in the set
				if (MatchRecursive(matchers, entries, bindings, new_excluded_entries, m_idx + 1)) {
					// we found a match for this path! success
					return true;
				} else {
					// we did not find a match! remove any bindings we added in the call to Match()
					bindings.erase(bindings.begin() + previous_binding_count, bindings.end());
				}
			}
		}
		return false;
	}

	template <class T, class MATCHER>
	static bool Match(vector<unique_ptr<MATCHER>> &matchers, vector<T *> &entries, vector<T *> &bindings,
	                  Policy policy) {
		if (policy == Policy::ORDERED) {
			// ordered policy, count has to match
			if (matchers.size() != entries.size()) {
				return false;
			}
			// now entries have to match in order
			for (idx_t i = 0; i < matchers.size(); i++) {
				if (!matchers[i]->Match(entries[i], bindings)) {
					return false;
				}
			}
			return true;
		} else {
			if (policy == Policy::UNORDERED && matchers.size() != entries.size()) {
				// unordered policy, count does not match: no match
				return false;
			} else if (policy == Policy::SOME && matchers.size() > entries.size()) {
				// some policy, every matcher has to match a unique entry
				// this is not possible if there are more matchers than entries
				return false;
			}
			// now perform the actual matching
			// every matcher has to match a UNIQUE entry
			// we perform this matching in a recursive way
			unordered_set<idx_t> excluded_entries;
			if (!MatchRecursive(matchers, entries, bindings, excluded_entries)) {
				return false;
			}
			return true;
		}
	}

	template <class T, class MATCHER>
	static bool Match(vector<unique_ptr<MATCHER>> &matchers, vector<unique_ptr<T>> &entries, vector<T *> &bindings,
	                  Policy policy) {
		// convert vector of unique_ptr to vector of normal pointers
		vector<T *> ptr_entries;
		for (auto &entry : entries) {
			ptr_entries.push_back(entry.get());
		}
		// then just call the normal match function
		return Match(matchers, ptr_entries, bindings, policy);
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/matcher/type_matcher.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The TypeMatcher class contains a set of matchers that can be used to pattern match TypeIds for Rules
class TypeMatcher {
public:
	virtual ~TypeMatcher() {
	}

	virtual bool Match(const LogicalType &type) = 0;
};

//! The SpecificTypeMatcher class matches only a single specified type
class SpecificTypeMatcher : public TypeMatcher {
public:
	explicit SpecificTypeMatcher(LogicalType type) : type(type) {
	}

	bool Match(const LogicalType &type_p) override {
		return type_p == this->type;
	}

private:
	LogicalType type;
};

//! The NumericTypeMatcher class matches any numeric type (DECIMAL, INTEGER, etc...)
class NumericTypeMatcher : public TypeMatcher {
public:
	bool Match(const LogicalType &type) override {
		return type.IsNumeric();
	}
};

//! The IntegerTypeMatcher class matches only integer types (INTEGER, SMALLINT, TINYINT, BIGINT)
class IntegerTypeMatcher : public TypeMatcher {
public:
	bool Match(const LogicalType &type) override {
		return type.IsIntegral();
	}
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/matcher/function_matcher.hpp
//
//
//===----------------------------------------------------------------------===//





#include <algorithm>

namespace duckdb {

//! The FunctionMatcher class contains a set of matchers that can be used to pattern match specific functions
class FunctionMatcher {
public:
	virtual ~FunctionMatcher() {
	}

	virtual bool Match(string &name) = 0;

	static bool Match(unique_ptr<FunctionMatcher> &matcher, string &name) {
		if (!matcher) {
			return true;
		}
		return matcher->Match(name);
	}
};

//! The SpecificFunctionMatcher class matches a single specified function name
class SpecificFunctionMatcher : public FunctionMatcher {
public:
	explicit SpecificFunctionMatcher(string name) : name(move(name)) {
	}

	bool Match(string &name) override {
		return name == this->name;
	}

private:
	string name;
};

//! The ManyFunctionMatcher class matches a set of functions
class ManyFunctionMatcher : public FunctionMatcher {
public:
	explicit ManyFunctionMatcher(unordered_set<string> names) : names(move(names)) {
	}

	bool Match(string &name) override {
		return names.find(name) != names.end();
	}

private:
	unordered_set<string> names;
};

} // namespace duckdb



namespace duckdb {

//! The ExpressionMatcher class contains a set of matchers that can be used to pattern match Expressions
class ExpressionMatcher {
public:
	explicit ExpressionMatcher(ExpressionClass type = ExpressionClass::INVALID) : expr_class(type) {
	}
	virtual ~ExpressionMatcher() {
	}

	//! Checks if the given expression matches this ExpressionMatcher. If it does, the expression is appended to the
	//! bindings list and true is returned. Otherwise, false is returned.
	virtual bool Match(Expression *expr, vector<Expression *> &bindings);

	//! The ExpressionClass of the to-be-matched expression. ExpressionClass::INVALID for ANY.
	ExpressionClass expr_class;
	//! Matcher for the ExpressionType of the operator (nullptr for ANY)
	unique_ptr<ExpressionTypeMatcher> expr_type;
	//! Matcher for the return_type of the expression (nullptr for ANY)
	unique_ptr<TypeMatcher> type;
};

//! The ExpressionEqualityMatcher matches on equality with another (given) expression
class ExpressionEqualityMatcher : public ExpressionMatcher {
public:
	explicit ExpressionEqualityMatcher(Expression *expr)
	    : ExpressionMatcher(ExpressionClass::INVALID), expression(expr) {
	}

	bool Match(Expression *expr, vector<Expression *> &bindings) override;

private:
	Expression *expression;
};

class ConstantExpressionMatcher : public ExpressionMatcher {
public:
	ConstantExpressionMatcher() : ExpressionMatcher(ExpressionClass::BOUND_CONSTANT) {
	}
};

class CaseExpressionMatcher : public ExpressionMatcher {
public:
	CaseExpressionMatcher() : ExpressionMatcher(ExpressionClass::BOUND_CASE) {
	}

	bool Match(Expression *expr_, vector<Expression *> &bindings) override;
};

class ComparisonExpressionMatcher : public ExpressionMatcher {
public:
	ComparisonExpressionMatcher()
	    : ExpressionMatcher(ExpressionClass::BOUND_COMPARISON), policy(SetMatcher::Policy::INVALID) {
	}
	//! The matchers for the child expressions
	vector<unique_ptr<ExpressionMatcher>> matchers;
	//! The set matcher matching policy to use
	SetMatcher::Policy policy;

	bool Match(Expression *expr_, vector<Expression *> &bindings) override;
};

class CastExpressionMatcher : public ExpressionMatcher {
public:
	CastExpressionMatcher() : ExpressionMatcher(ExpressionClass::BOUND_CAST) {
	}
	//! The matcher for the child expressions
	unique_ptr<ExpressionMatcher> matcher;

	bool Match(Expression *expr_, vector<Expression *> &bindings) override;
};

class InClauseExpressionMatcher : public ExpressionMatcher {
public:
	InClauseExpressionMatcher() : ExpressionMatcher(ExpressionClass::BOUND_OPERATOR) {
	}
	//! The matchers for the child expressions
	vector<unique_ptr<ExpressionMatcher>> matchers;
	//! The set matcher matching policy to use
	SetMatcher::Policy policy;

	bool Match(Expression *expr_, vector<Expression *> &bindings) override;
};

class ConjunctionExpressionMatcher : public ExpressionMatcher {
public:
	ConjunctionExpressionMatcher()
	    : ExpressionMatcher(ExpressionClass::BOUND_CONJUNCTION), policy(SetMatcher::Policy::INVALID) {
	}
	//! The matchers for the child expressions
	vector<unique_ptr<ExpressionMatcher>> matchers;
	//! The set matcher matching policy to use
	SetMatcher::Policy policy;

	bool Match(Expression *expr_, vector<Expression *> &bindings) override;
};

class FunctionExpressionMatcher : public ExpressionMatcher {
public:
	FunctionExpressionMatcher() : ExpressionMatcher(ExpressionClass::BOUND_FUNCTION) {
	}
	//! The matchers for the child expressions
	vector<unique_ptr<ExpressionMatcher>> matchers;
	//! The set matcher matching policy to use
	SetMatcher::Policy policy;
	//! The function name to match
	unique_ptr<FunctionMatcher> function;

	bool Match(Expression *expr_, vector<Expression *> &bindings) override;
};

//! The FoldableConstant matcher matches any expression that is foldable into a constant by the ExpressionExecutor (i.e.
//! scalar but not aggregate/window/parameter)
class FoldableConstantMatcher : public ExpressionMatcher {
public:
	FoldableConstantMatcher() : ExpressionMatcher(ExpressionClass::INVALID) {
	}

	bool Match(Expression *expr, vector<Expression *> &bindings) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_filter.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalFilter represents a filter operation (e.g. WHERE or HAVING clause)
class LogicalFilter : public LogicalOperator {
public:
	explicit LogicalFilter(unique_ptr<Expression> expression);
	LogicalFilter();

	vector<idx_t> projection_map;

public:
	vector<ColumnBinding> GetColumnBindings() override;

	bool SplitPredicates() {
		return SplitPredicates(expressions);
	}
	//! Splits up the predicates of the LogicalFilter into a set of predicates
	//! separated by AND Returns whether or not any splits were made
	static bool SplitPredicates(vector<unique_ptr<Expression>> &expressions);

protected:
	void ResolveTypes() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_get.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! LogicalGet represents a scan operation from a data source
class LogicalGet : public LogicalOperator {
public:
	LogicalGet(idx_t table_index, TableFunction function, unique_ptr<FunctionData> bind_data,
	           vector<LogicalType> returned_types, vector<string> returned_names);

	//! The table index in the current bind context
	idx_t table_index;
	//! The function that is called
	TableFunction function;
	//! The bind data of the function
	unique_ptr<FunctionData> bind_data;
	//! The types of ALL columns that can be returned by the table function
	vector<LogicalType> returned_types;
	//! The names of ALL columns that can be returned by the table function
	vector<string> names;
	//! Bound column IDs
	vector<column_t> column_ids;
	//! Filters pushed down for table scan
	TableFilterSet table_filters;

	string GetName() const override;
	string ParamsToString() const override;
	//! Returns the underlying table that is being scanned, or nullptr if there is none
	TableCatalogEntry *GetTable() const;

public:
	vector<ColumnBinding> GetColumnBindings() override;

	idx_t EstimateCardinality(ClientContext &context) override;

protected:
	void ResolveTypes() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_insert.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalInsert represents an insertion of data into a base table
class LogicalInsert : public LogicalOperator {
public:
	explicit LogicalInsert(TableCatalogEntry *table)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_INSERT), table(table), table_index(0), return_chunk(false) {
	}

	vector<vector<unique_ptr<Expression>>> insert_values;
	//! The insertion map ([table_index -> index in result, or DConstants::INVALID_INDEX if not specified])
	vector<idx_t> column_index_map;
	//! The expected types for the INSERT statement (obtained from the column types)
	vector<LogicalType> expected_types;
	//! The base table to insert into
	TableCatalogEntry *table;
	idx_t table_index;
	//! if returning option is used, return actual chunk to projection
	bool return_chunk;
	//! The default statements used by the table
	vector<unique_ptr<Expression>> bound_defaults;

protected:
	vector<ColumnBinding> GetColumnBindings() override {
		if (return_chunk) {
			return GenerateColumnBindings(table_index, table->columns.size());
		}
		return {ColumnBinding(0, 0)};
	}

	void ResolveTypes() override {
		if (return_chunk) {
			types = table->GetTypes();
		} else {
			types.emplace_back(LogicalType::BIGINT);
		}
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_limit.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalLimit represents a LIMIT clause
class LogicalLimit : public LogicalOperator {
public:
	LogicalLimit(int64_t limit_val, int64_t offset_val, unique_ptr<Expression> limit, unique_ptr<Expression> offset);

	//! Limit and offset values in case they are constants, used in optimizations.
	int64_t limit_val;
	int64_t offset_val;
	//! The maximum amount of elements to emit
	unique_ptr<Expression> limit;
	//! The offset from the start to begin emitting elements
	unique_ptr<Expression> offset;

public:
	vector<ColumnBinding> GetColumnBindings() override;

	idx_t EstimateCardinality(ClientContext &context) override;

protected:
	void ResolveTypes() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_order.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! LogicalOrder represents an ORDER BY clause, sorting the data
class LogicalOrder : public LogicalOperator {
public:
	explicit LogicalOrder(vector<BoundOrderByNode> orders)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_ORDER_BY), orders(move(orders)) {
	}

	vector<BoundOrderByNode> orders;

	string ParamsToString() const override {
		string result;
		for (idx_t i = 0; i < orders.size(); i++) {
			if (i > 0) {
				result += "\n";
			}
			result += orders[i].expression->GetName();
		}
		return result;
	}

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return children[0]->GetColumnBindings();
	}

protected:
	void ResolveTypes() override {
		types = children[0]->types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_pragma.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! LogicalSimple represents a simple logical operator that only passes on the parse info
class LogicalPragma : public LogicalOperator {
public:
	LogicalPragma(PragmaFunction function_p, PragmaInfo info_p)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_PRAGMA), function(move(function_p)), info(move(info_p)) {
	}

	//! The pragma function to call
	PragmaFunction function;
	//! The context of the call
	PragmaInfo info;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BOOLEAN);
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_prepare.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class TableCatalogEntry;

class LogicalPrepare : public LogicalOperator {
public:
	LogicalPrepare(string name, shared_ptr<PreparedStatementData> prepared, unique_ptr<LogicalOperator> logical_plan)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_PREPARE), name(name), prepared(move(prepared)) {
		children.push_back(move(logical_plan));
	}

	string name;
	shared_ptr<PreparedStatementData> prepared;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BOOLEAN);
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_projection.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalProjection represents the projection list in a SELECT clause
class LogicalProjection : public LogicalOperator {
public:
	LogicalProjection(idx_t table_index, vector<unique_ptr<Expression>> select_list);

	idx_t table_index;

public:
	vector<ColumnBinding> GetColumnBindings() override;

protected:
	void ResolveTypes() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_recursive_cte.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class LogicalRecursiveCTE : public LogicalOperator {
public:
	LogicalRecursiveCTE(idx_t table_index, idx_t column_count, bool union_all, unique_ptr<LogicalOperator> top,
	                    unique_ptr<LogicalOperator> bottom, LogicalOperatorType type)
	    : LogicalOperator(type), union_all(union_all), table_index(table_index), column_count(column_count) {
		D_ASSERT(type == LogicalOperatorType::LOGICAL_RECURSIVE_CTE);
		children.push_back(move(top));
		children.push_back(move(bottom));
	}

	bool union_all;
	idx_t table_index;
	idx_t column_count;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return GenerateColumnBindings(table_index, column_count);
	}

protected:
	void ResolveTypes() override {
		types = children[0]->types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_cteref.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! LogicalChunkGet represents a scan operation from a ChunkCollection
class LogicalCTERef : public LogicalOperator {
public:
	LogicalCTERef(idx_t table_index, idx_t cte_index, vector<LogicalType> types, vector<string> colnames)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_CTE_REF), table_index(table_index), cte_index(cte_index) {
		D_ASSERT(types.size() > 0);
		chunk_types = types;
		bound_columns = colnames;
	}

	vector<string> bound_columns;
	//! The table index in the current bind context
	idx_t table_index;
	//! CTE index
	idx_t cte_index;
	//! The types of the chunk
	vector<LogicalType> chunk_types;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return GenerateColumnBindings(table_index, chunk_types.size());
	}

protected:
	void ResolveTypes() override {
		// types are resolved in the constructor
		this->types = chunk_types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_sample.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! LogicalSample represents a SAMPLE clause
class LogicalSample : public LogicalOperator {
public:
	LogicalSample(unique_ptr<SampleOptions> sample_options_p, unique_ptr<LogicalOperator> child);

	//! The sample options
	unique_ptr<SampleOptions> sample_options;

public:
	vector<ColumnBinding> GetColumnBindings() override;

	idx_t EstimateCardinality(ClientContext &context) override;

protected:
	void ResolveTypes() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_set.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class LogicalSet : public LogicalOperator {
public:
	LogicalSet(std::string name_p, Value value_p, SetScope scope_p)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_SET), name(name_p), value(value_p), scope(scope_p) {
	}

	std::string name;
	Value value;
	SetScope scope;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BOOLEAN);
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_set_operation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class LogicalSetOperation : public LogicalOperator {
public:
	LogicalSetOperation(idx_t table_index, idx_t column_count, unique_ptr<LogicalOperator> top,
	                    unique_ptr<LogicalOperator> bottom, LogicalOperatorType type)
	    : LogicalOperator(type), table_index(table_index), column_count(column_count) {
		D_ASSERT(type == LogicalOperatorType::LOGICAL_UNION || type == LogicalOperatorType::LOGICAL_EXCEPT ||
		         type == LogicalOperatorType::LOGICAL_INTERSECT);
		children.push_back(move(top));
		children.push_back(move(bottom));
	}

	idx_t table_index;
	idx_t column_count;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return GenerateColumnBindings(table_index, column_count);
	}

protected:
	void ResolveTypes() override {
		types = children[0]->types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_show.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class LogicalShow : public LogicalOperator {
public:
	explicit LogicalShow(unique_ptr<LogicalOperator> plan) : LogicalOperator(LogicalOperatorType::LOGICAL_SHOW) {
		children.push_back(move(plan));
	}

	vector<LogicalType> types_select;
	vector<string> aliases;

protected:
	void ResolveTypes() override {
		types = {LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR,
		         LogicalType::VARCHAR, LogicalType::VARCHAR, LogicalType::VARCHAR};
	}
	vector<ColumnBinding> GetColumnBindings() override {
		return {ColumnBinding(0, 0), ColumnBinding(0, 1), ColumnBinding(0, 2),
		        ColumnBinding(0, 3), ColumnBinding(0, 4), ColumnBinding(0, 5)};
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_simple.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! LogicalSimple represents a simple logical operator that only passes on the parse info
class LogicalSimple : public LogicalOperator {
public:
	LogicalSimple(LogicalOperatorType type, unique_ptr<ParseInfo> info) : LogicalOperator(type), info(move(info)) {
	}

	unique_ptr<ParseInfo> info;

protected:
	void ResolveTypes() override {
		types.emplace_back(LogicalType::BOOLEAN);
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_top_n.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! LogicalTopN represents a comibination of ORDER BY and LIMIT clause, using Min/Max Heap
class LogicalTopN : public LogicalOperator {
public:
	LogicalTopN(vector<BoundOrderByNode> orders, int64_t limit, int64_t offset)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_TOP_N), orders(move(orders)), limit(limit), offset(offset) {
	}

	vector<BoundOrderByNode> orders;
	//! The maximum amount of elements to emit
	int64_t limit;
	//! The offset from the start to begin emitting elements
	int64_t offset;

public:
	vector<ColumnBinding> GetColumnBindings() override {
		return children[0]->GetColumnBindings();
	}

protected:
	void ResolveTypes() override {
		types = children[0]->types;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_unnest.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalAggregate represents an aggregate operation with (optional) GROUP BY
//! operator.
class LogicalUnnest : public LogicalOperator {
public:
	explicit LogicalUnnest(idx_t unnest_index)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_UNNEST), unnest_index(unnest_index) {
	}

	idx_t unnest_index;

public:
	vector<ColumnBinding> GetColumnBindings() override;

protected:
	void ResolveTypes() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_update.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class LogicalUpdate : public LogicalOperator {
public:
	explicit LogicalUpdate(TableCatalogEntry *table)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_UPDATE), table(table), table_index(0), return_chunk(false) {
	}

	//! The base table to update
	TableCatalogEntry *table;
	//! table catalog index
	idx_t table_index;
	//! if returning option is used, return the update chunk
	bool return_chunk;
	vector<column_t> columns;
	vector<unique_ptr<Expression>> bound_defaults;
	bool update_is_del_and_insert;

protected:
	vector<ColumnBinding> GetColumnBindings() override {
		if (return_chunk) {
			return GenerateColumnBindings(table_index, table->columns.size());
		}
		return {ColumnBinding(0, 0)};
	}

	void ResolveTypes() override {
		if (return_chunk) {
			types = table->GetTypes();
		} else {
			types.emplace_back(LogicalType::BIGINT);
		}
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/operator/logical_window.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! LogicalAggregate represents an aggregate operation with (optional) GROUP BY
//! operator.
class LogicalWindow : public LogicalOperator {
public:
	explicit LogicalWindow(idx_t window_index)
	    : LogicalOperator(LogicalOperatorType::LOGICAL_WINDOW), window_index(window_index) {
	}

	idx_t window_index;

public:
	vector<ColumnBinding> GetColumnBindings() override;

protected:
	void ResolveTypes() override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/algebraic_functions.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct AvgFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CovarSampFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CovarPopFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct Corr {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StdDevSampFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StdDevPopFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct VarPopFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct VarSampFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct VarianceFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StandardErrorOfTheMeanFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/sum_helpers.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

static inline void KahanAddInternal(double input, double &summed, double &err) {
	double diff = input - err;
	double newval = summed + diff;
	err = (newval - summed) - diff;
	summed = newval;
}

template <class T>
struct SumState {
	bool isset;
	T value;

	void Initialize() {
		this->isset = false;
	}

	void Combine(const SumState<T> &other) {
		this->isset = other.isset || this->isset;
		this->value += other.value;
	}
};

struct KahanSumState {
	bool isset;
	double value;
	double err;

	void Initialize() {
		this->isset = false;
		this->err = 0.0;
	}

	void Combine(const KahanSumState &other) {
		this->isset = other.isset || this->isset;
		KahanAddInternal(other.value, this->value, this->err);
		KahanAddInternal(other.err, this->value, this->err);
	}
};

struct RegularAdd {
	template <class STATE, class T>
	static void AddNumber(STATE &state, T input) {
		state.value += input;
	}

	template <class STATE, class T>
	static void AddConstant(STATE &state, T input, idx_t count) {
		state.value += input * count;
	}
};

struct KahanAdd {
	template <class STATE, class T>
	static void AddNumber(STATE &state, T input) {
		KahanAddInternal(input, state.value, state.err);
	}

	template <class STATE, class T>
	static void AddConstant(STATE &state, T input, idx_t count) {
		KahanAddInternal(input * count, state.value, state.err);
	}
};

struct HugeintAdd {
	static void AddValue(hugeint_t &result, uint64_t value, int positive) {
		// integer summation taken from Tim Gubner et al. - Efficient Query Processing
		// with Optimistically Compressed Hash Tables & Strings in the USSR

		// add the value to the lower part of the hugeint
		result.lower += value;
		// now handle overflows
		int overflow = result.lower < value;
		// we consider two situations:
		// (1) input[idx] is positive, and current value is lower than value: overflow
		// (2) input[idx] is negative, and current value is higher than value: underflow
		if (!(overflow ^ positive)) {
			// in the case of an overflow or underflow we either increment or decrement the upper base
			// positive: +1, negative: -1
			result.upper += -1 + 2 * positive;
		}
	}

	template <class STATE, class T>
	static void AddNumber(STATE &state, T input) {
		AddValue(state.value, uint64_t(input), input >= 0);
	}

	template <class STATE, class T>
	static void AddConstant(STATE &state, T input, idx_t count) {
		// add a constant X number of times
		// fast path: check if value * count fits into a uint64_t
		// note that we check if value * VECTOR_SIZE fits in a uint64_t to avoid having to actually do a division
		// this is still a pretty high number (18014398509481984) so most positive numbers will fit
		if (input >= 0 && uint64_t(input) < (NumericLimits<uint64_t>::Maximum() / STANDARD_VECTOR_SIZE)) {
			// if it does just multiply it and add the value
			uint64_t value = uint64_t(input) * count;
			AddValue(state.value, value, 1);
		} else {
			// if it doesn't fit we have two choices
			// either we loop over count and add the values individually
			// or we convert to a hugeint and multiply the hugeint
			// the problem is that hugeint multiplication is expensive
			// hence we switch here: with a low count we do the loop
			// with a high count we do the hugeint multiplication
			if (count < 8) {
				for (idx_t i = 0; i < count; i++) {
					AddValue(state.value, uint64_t(input), input >= 0);
				}
			} else {
				hugeint_t addition = hugeint_t(input) * count;
				state.value += addition;
			}
		}
	}
};

template <class STATEOP, class ADDOP>
struct BaseSumOperation {
	template <class STATE>
	static void Initialize(STATE *state) {
		state->value = 0;
		STATEOP::template Initialize<STATE>(state);
	}

	template <class STATE, class OP>
	static void Combine(const STATE &source, STATE *target, AggregateInputData &aggr_input_data) {
		STATEOP::template Combine<STATE>(source, target, aggr_input_data);
	}

	template <class INPUT_TYPE, class STATE, class OP>
	static void Operation(STATE *state, AggregateInputData &, INPUT_TYPE *input, ValidityMask &mask, idx_t idx) {
		STATEOP::template AddValues<STATE>(state, 1);
		ADDOP::template AddNumber<STATE, INPUT_TYPE>(*state, input[idx]);
	}

	template <class INPUT_TYPE, class STATE, class OP>
	static void ConstantOperation(STATE *state, AggregateInputData &, INPUT_TYPE *input, ValidityMask &mask,
	                              idx_t count) {
		STATEOP::template AddValues<STATE>(state, count);
		ADDOP::template AddConstant<STATE, INPUT_TYPE>(*state, *input, count);
	}

	static bool IgnoreNull() {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/algebraic/covar.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct CovarState {
	uint64_t count;
	double meanx;
	double meany;
	double co_moment;
};

struct CovarOperation {
	template <class STATE>
	static void Initialize(STATE *state) {
		state->count = 0;
		state->meanx = 0;
		state->meany = 0;
		state->co_moment = 0;
	}

	template <class A_TYPE, class B_TYPE, class STATE, class OP>
	static void Operation(STATE *state, AggregateInputData &, A_TYPE *x_data, B_TYPE *y_data, ValidityMask &amask,
	                      ValidityMask &bmask, idx_t xidx, idx_t yidx) {
		// update running mean and d^2
		const uint64_t n = ++(state->count);

		const auto x = x_data[xidx];
		const double dx = (x - state->meanx);
		const double meanx = state->meanx + dx / n;

		const auto y = y_data[yidx];
		const double dy = (y - state->meany);
		const double meany = state->meany + dy / n;

		const double C = state->co_moment + dx * (y - meany);

		state->meanx = meanx;
		state->meany = meany;
		state->co_moment = C;
	}

	template <class STATE, class OP>
	static void Combine(const STATE &source, STATE *target, AggregateInputData &) {
		if (target->count == 0) {
			*target = source;
		} else if (source.count > 0) {
			const auto count = target->count + source.count;
			const auto meanx = (source.count * source.meanx + target->count * target->meanx) / count;
			const auto meany = (source.count * source.meany + target->count * target->meany) / count;

			//  Schubert and Gertz SSDBM 2018, equation 21
			const auto deltax = target->meanx - source.meanx;
			const auto deltay = target->meany - source.meany;
			target->co_moment =
			    source.co_moment + target->co_moment + deltax * deltay * source.count * target->count / count;
			target->meanx = meanx;
			target->meany = meany;
			target->count = count;
		}
	}

	static bool IgnoreNull() {
		return true;
	}
};

struct CovarPopOperation : public CovarOperation {
	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->count == 0) {
			mask.SetInvalid(idx);
		} else {
			target[idx] = state->co_moment / state->count;
		}
	}
};

struct CovarSampOperation : public CovarOperation {
	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if ((state->count) < 2) {
			mask.SetInvalid(idx);
		} else {
			target[idx] = state->co_moment / (state->count - 1);
		}
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/algebraic/stddev.hpp
//
//
//===----------------------------------------------------------------------===//




#include <ctgmath>

namespace duckdb {

struct StddevState {
	uint64_t count;  //  n
	double mean;     //  M1
	double dsquared; //  M2
};

// Streaming approximate standard deviation using Welford's
// method, DOI: 10.2307/1266577
struct STDDevBaseOperation {
	template <class STATE>
	static void Initialize(STATE *state) {
		state->count = 0;
		state->mean = 0;
		state->dsquared = 0;
	}

	template <class INPUT_TYPE, class STATE, class OP>
	static void Operation(STATE *state, AggregateInputData &, INPUT_TYPE *input_data, ValidityMask &mask, idx_t idx) {
		// update running mean and d^2
		state->count++;
		const double input = input_data[idx];
		const double mean_differential = (input - state->mean) / state->count;
		const double new_mean = state->mean + mean_differential;
		const double dsquared_increment = (input - new_mean) * (input - state->mean);
		const double new_dsquared = state->dsquared + dsquared_increment;

		state->mean = new_mean;
		state->dsquared = new_dsquared;
	}

	template <class INPUT_TYPE, class STATE, class OP>
	static void ConstantOperation(STATE *state, AggregateInputData &aggr_input_data, INPUT_TYPE *input_data,
	                              ValidityMask &mask, idx_t count) {
		for (idx_t i = 0; i < count; i++) {
			Operation<INPUT_TYPE, STATE, OP>(state, aggr_input_data, input_data, mask, 0);
		}
	}

	template <class STATE, class OP>
	static void Combine(const STATE &source, STATE *target, AggregateInputData &) {
		if (target->count == 0) {
			*target = source;
		} else if (source.count > 0) {
			const auto count = target->count + source.count;
			const auto mean = (source.count * source.mean + target->count * target->mean) / count;
			const auto delta = source.mean - target->mean;
			target->dsquared =
			    source.dsquared + target->dsquared + delta * delta * source.count * target->count / count;
			target->mean = mean;
			target->count = count;
		}
	}

	static bool IgnoreNull() {
		return true;
	}
};

struct VarSampOperation : public STDDevBaseOperation {
	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->count <= 1) {
			mask.SetInvalid(idx);
		} else {
			target[idx] = state->dsquared / (state->count - 1);
			if (!Value::DoubleIsFinite(target[idx])) {
				throw OutOfRangeException("VARSAMP is out of range!");
			}
		}
	}
};

struct VarPopOperation : public STDDevBaseOperation {
	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->count == 0) {
			mask.SetInvalid(idx);
		} else {
			target[idx] = state->count > 1 ? (state->dsquared / state->count) : 0;
			if (!Value::DoubleIsFinite(target[idx])) {
				throw OutOfRangeException("VARPOP is out of range!");
			}
		}
	}
};

struct STDDevSampOperation : public STDDevBaseOperation {
	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->count <= 1) {
			mask.SetInvalid(idx);
		} else {
			target[idx] = sqrt(state->dsquared / (state->count - 1));
			if (!Value::DoubleIsFinite(target[idx])) {
				throw OutOfRangeException("STDDEV_SAMP is out of range!");
			}
		}
	}
};

struct STDDevPopOperation : public STDDevBaseOperation {
	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->count == 0) {
			mask.SetInvalid(idx);
		} else {
			target[idx] = state->count > 1 ? sqrt(state->dsquared / state->count) : 0;
			if (!Value::DoubleIsFinite(target[idx])) {
				throw OutOfRangeException("STDDEV_POP is out of range!");
			}
		}
	}
};

struct StandardErrorOfTheMeanOperation : public STDDevBaseOperation {
	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->count == 0) {
			mask.SetInvalid(idx);
		} else {
			target[idx] = sqrt(state->dsquared / state->count) / sqrt((state->count));
			if (!Value::DoubleIsFinite(target[idx])) {
				throw OutOfRangeException("SEM is out of range!");
			}
		}
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/algebraic/corr.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

struct CorrState {
	CovarState cov_pop;
	StddevState dev_pop_x;
	StddevState dev_pop_y;
};

// Returns the correlation coefficient for non-null pairs in a group.
// CORR(y, x) = COVAR_POP(y, x) / (STDDEV_POP(x) * STDDEV_POP(y))
struct CorrOperation {
	template <class STATE>
	static void Initialize(STATE *state) {
		CovarOperation::Initialize<CovarState>(&state->cov_pop);
		STDDevBaseOperation::Initialize<StddevState>(&state->dev_pop_x);
		STDDevBaseOperation::Initialize<StddevState>(&state->dev_pop_y);
	}

	template <class A_TYPE, class B_TYPE, class STATE, class OP>
	static void Operation(STATE *state, AggregateInputData &aggr_input_data, A_TYPE *x_data, B_TYPE *y_data,
	                      ValidityMask &amask, ValidityMask &bmask, idx_t xidx, idx_t yidx) {
		CovarOperation::Operation<A_TYPE, B_TYPE, CovarState, OP>(&state->cov_pop, aggr_input_data, x_data, y_data,
		                                                          amask, bmask, xidx, yidx);
		STDDevBaseOperation::Operation<A_TYPE, StddevState, OP>(&state->dev_pop_x, aggr_input_data, x_data, amask,
		                                                        xidx);
		STDDevBaseOperation::Operation<B_TYPE, StddevState, OP>(&state->dev_pop_y, aggr_input_data, y_data, bmask,
		                                                        yidx);
	}

	template <class STATE, class OP>
	static void Combine(const STATE &source, STATE *target, AggregateInputData &aggr_input_data) {
		CovarOperation::Combine<CovarState, OP>(source.cov_pop, &target->cov_pop, aggr_input_data);
		STDDevBaseOperation::Combine<StddevState, OP>(source.dev_pop_x, &target->dev_pop_x, aggr_input_data);
		STDDevBaseOperation::Combine<StddevState, OP>(source.dev_pop_y, &target->dev_pop_y, aggr_input_data);
	}

	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->cov_pop.count == 0 || state->dev_pop_x.count == 0 || state->dev_pop_y.count == 0) {
			mask.SetInvalid(idx);
		} else {
			auto cov = state->cov_pop.co_moment / state->cov_pop.count;
			auto std_x = state->dev_pop_x.count > 1 ? sqrt(state->dev_pop_x.dsquared / state->dev_pop_x.count) : 0;
			if (!Value::DoubleIsFinite(std_x)) {
				throw OutOfRangeException("STDDEV_POP for X is out of range!");
			}
			auto std_y = state->dev_pop_y.count > 1 ? sqrt(state->dev_pop_y.dsquared / state->dev_pop_y.count) : 0;
			if (!Value::DoubleIsFinite(std_y)) {
				throw OutOfRangeException("STDDEV_POP for Y is out of range!");
			}
			if (std_x * std_y == 0) {
				mask.SetInvalid(idx);
				return;
			}
			target[idx] = cov / (std_x * std_y);
		}
	}

	static bool IgnoreNull() {
		return true;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/holistic_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct QuantileFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ModeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ApproximateQuantileFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ReservoirQuantileFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #8
// See the end of this file for a list

/*
 * Licensed to Derrick R. Burns under one or more
 * contributor license agreements.  See the NOTICES 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.
 */



#include <algorithm>
#include <cfloat>
#include <cmath>
#include <queue>
#include <utility>
#include <vector>

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif


namespace duckdb_tdigest {

using Value = double;
using Weight = double;
using Index = size_t;

const size_t kHighWater = 40000;
const double pi = 3.14159265358979323846;
class Centroid {
public:
	Centroid() : Centroid(0.0, 0.0) {
	}

	Centroid(Value mean, Weight weight) : mean_(mean), weight_(weight) {
	}

	inline Value mean() const noexcept {
		return mean_;
	}

	inline Weight weight() const noexcept {
		return weight_;
	}

	inline void add(const Centroid &c) {
		//    CHECK_GT(c.weight_, 0);
		if (weight_ != 0.0) {
			weight_ += c.weight_;
			mean_ += c.weight_ * (c.mean_ - mean_) / weight_;
		} else {
			weight_ = c.weight_;
			mean_ = c.mean_;
		}
	}

private:
	Value mean_ = 0;
	Weight weight_ = 0;
};

struct CentroidList {
	explicit CentroidList(const std::vector<Centroid> &s) : iter(s.cbegin()), end(s.cend()) {
	}
	std::vector<Centroid>::const_iterator iter;
	std::vector<Centroid>::const_iterator end;

	bool advance() {
		return ++iter != end;
	}
};

class CentroidListComparator {
public:
	CentroidListComparator() {
	}

	bool operator()(const CentroidList &left, const CentroidList &right) const {
		return left.iter->mean() > right.iter->mean();
	}
};

using CentroidListQueue = std::priority_queue<CentroidList, std::vector<CentroidList>, CentroidListComparator>;

struct CentroidComparator {
	bool operator()(const Centroid &a, const Centroid &b) const {
		return a.mean() < b.mean();
	}
};

class TDigest {
	class TDigestComparator {
	public:
		TDigestComparator() {
		}

		bool operator()(const TDigest *left, const TDigest *right) const {
			return left->totalSize() > right->totalSize();
		}
	};

	using TDigestQueue = std::priority_queue<const TDigest *, std::vector<const TDigest *>, TDigestComparator>;

public:
	TDigest() : TDigest(1000) {
	}

	explicit TDigest(Value compression) : TDigest(compression, 0) {
	}

	TDigest(Value compression, Index bufferSize) : TDigest(compression, bufferSize, 0) {
	}

	TDigest(Value compression, Index unmergedSize, Index mergedSize)
	    : compression_(compression), maxProcessed_(processedSize(mergedSize, compression)),
	      maxUnprocessed_(unprocessedSize(unmergedSize, compression)) {
		processed_.reserve(maxProcessed_);
		unprocessed_.reserve(maxUnprocessed_ + 1);
	}

	TDigest(std::vector<Centroid> &&processed, std::vector<Centroid> &&unprocessed, Value compression,
	        Index unmergedSize, Index mergedSize)
	    : TDigest(compression, unmergedSize, mergedSize) {
		processed_ = std::move(processed);
		unprocessed_ = std::move(unprocessed);

		processedWeight_ = weight(processed_);
		unprocessedWeight_ = weight(unprocessed_);
		if (!processed_.empty()) {
			min_ = std::min(min_, processed_[0].mean());
			max_ = std::max(max_, (processed_.cend() - 1)->mean());
		}
		updateCumulative();
	}

	static Weight weight(std::vector<Centroid> &centroids) noexcept {
		Weight w = 0.0;
		for (auto centroid : centroids) {
			w += centroid.weight();
		}
		return w;
	}

	TDigest &operator=(TDigest &&o) {
		compression_ = o.compression_;
		maxProcessed_ = o.maxProcessed_;
		maxUnprocessed_ = o.maxUnprocessed_;
		processedWeight_ = o.processedWeight_;
		unprocessedWeight_ = o.unprocessedWeight_;
		processed_ = std::move(o.processed_);
		unprocessed_ = std::move(o.unprocessed_);
		cumulative_ = std::move(o.cumulative_);
		min_ = o.min_;
		max_ = o.max_;
		return *this;
	}

	TDigest(TDigest &&o)
	    : TDigest(std::move(o.processed_), std::move(o.unprocessed_), o.compression_, o.maxUnprocessed_,
	              o.maxProcessed_) {
	}

	static inline Index processedSize(Index size, Value compression) noexcept {
		return (size == 0) ? static_cast<Index>(2 * std::ceil(compression)) : size;
	}

	static inline Index unprocessedSize(Index size, Value compression) noexcept {
		return (size == 0) ? static_cast<Index>(8 * std::ceil(compression)) : size;
	}

	// merge in another t-digest
	inline void merge(const TDigest *other) {
		std::vector<const TDigest *> others {other};
		add(others.cbegin(), others.cend());
	}

	const std::vector<Centroid> &processed() const {
		return processed_;
	}

	const std::vector<Centroid> &unprocessed() const {
		return unprocessed_;
	}

	Index maxUnprocessed() const {
		return maxUnprocessed_;
	}

	Index maxProcessed() const {
		return maxProcessed_;
	}

	inline void add(std::vector<const TDigest *> digests) {
		add(digests.cbegin(), digests.cend());
	}

	// merge in a vector of tdigests in the most efficient manner possible
	// in constant space
	// works for any value of kHighWater
	void add(std::vector<const TDigest *>::const_iterator iter, std::vector<const TDigest *>::const_iterator end) {
		if (iter != end) {
			auto size = std::distance(iter, end);
			TDigestQueue pq(TDigestComparator {});
			for (; iter != end; iter++) {
				pq.push((*iter));
			}
			std::vector<const TDigest *> batch;
			batch.reserve(size);

			size_t totalSize = 0;
			while (!pq.empty()) {
				auto td = pq.top();
				batch.push_back(td);
				pq.pop();
				totalSize += td->totalSize();
				if (totalSize >= kHighWater || pq.empty()) {
					mergeProcessed(batch);
					mergeUnprocessed(batch);
					processIfNecessary();
					batch.clear();
					totalSize = 0;
				}
			}
			updateCumulative();
		}
	}

	Weight processedWeight() const {
		return processedWeight_;
	}

	Weight unprocessedWeight() const {
		return unprocessedWeight_;
	}

	bool haveUnprocessed() const {
		return unprocessed_.size() > 0;
	}

	size_t totalSize() const {
		return processed_.size() + unprocessed_.size();
	}

	long totalWeight() const {
		return static_cast<long>(processedWeight_ + unprocessedWeight_);
	}

	// return the cdf on the t-digest
	Value cdf(Value x) {
		if (haveUnprocessed() || isDirty()) {
			process();
		}
		return cdfProcessed(x);
	}

	bool isDirty() {
		return processed_.size() > maxProcessed_ || unprocessed_.size() > maxUnprocessed_;
	}

	// return the cdf on the processed values
	Value cdfProcessed(Value x) const {
		if (processed_.empty()) {
			// no data to examin_e

			return 0.0;
		} else if (processed_.size() == 1) {
			// exactly one centroid, should have max_==min_
			auto width = max_ - min_;
			if (x < min_) {
				return 0.0;
			} else if (x > max_) {
				return 1.0;
			} else if (x - min_ <= width) {
				// min_ and max_ are too close together to do any viable interpolation
				return 0.5;
			} else {
				// interpolate if somehow we have weight > 0 and max_ != min_
				return (x - min_) / (max_ - min_);
			}
		} else {
			auto n = processed_.size();
			if (x <= min_) {
				return 0;
			}

			if (x >= max_) {
				return 1;
			}

			// check for the left tail
			if (x <= mean(0)) {

				// note that this is different than mean(0) > min_ ... this guarantees interpolation works
				if (mean(0) - min_ > 0) {
					return (x - min_) / (mean(0) - min_) * weight(0) / processedWeight_ / 2.0;
				} else {
					return 0;
				}
			}

			// and the right tail
			if (x >= mean(n - 1)) {
				if (max_ - mean(n - 1) > 0) {
					return 1.0 - (max_ - x) / (max_ - mean(n - 1)) * weight(n - 1) / processedWeight_ / 2.0;
				} else {
					return 1;
				}
			}

			CentroidComparator cc;
			auto iter = std::upper_bound(processed_.cbegin(), processed_.cend(), Centroid(x, 0), cc);

			auto i = std::distance(processed_.cbegin(), iter);
			auto z1 = x - (iter - 1)->mean();
			auto z2 = (iter)->mean() - x;
			return weightedAverage(cumulative_[i - 1], z2, cumulative_[i], z1) / processedWeight_;
		}
	}

	// this returns a quantile on the t-digest
	Value quantile(Value q) {
		if (haveUnprocessed() || isDirty()) {
			process();
		}
		return quantileProcessed(q);
	}

	// this returns a quantile on the currently processed values without changing the t-digest
	// the value will not represent the unprocessed values
	Value quantileProcessed(Value q) const {
		if (q < 0 || q > 1) {
			return NAN;
		}

		if (processed_.size() == 0) {
			// no sorted means no data, no way to get a quantile
			return NAN;
		} else if (processed_.size() == 1) {
			// with one data point, all quantiles lead to Rome

			return mean(0);
		}

		// we know that there are at least two sorted now
		auto n = processed_.size();

		// if values were stored in a sorted array, index would be the offset we are Weighterested in
		const auto index = q * processedWeight_;

		// at the boundaries, we return min_ or max_
		if (index <= weight(0) / 2.0) {
			return min_ + 2.0 * index / weight(0) * (mean(0) - min_);
		}

		auto iter = std::lower_bound(cumulative_.cbegin(), cumulative_.cend(), index);

		if (iter + 1 != cumulative_.cend()) {
			auto i = std::distance(cumulative_.cbegin(), iter);
			auto z1 = index - *(iter - 1);
			auto z2 = *(iter)-index;
			// LOG(INFO) << "z2 " << z2 << " index " << index << " z1 " << z1;
			return weightedAverage(mean(i - 1), z2, mean(i), z1);
		}
		auto z1 = index - processedWeight_ - weight(n - 1) / 2.0;
		auto z2 = weight(n - 1) / 2 - z1;
		return weightedAverage(mean(n - 1), z1, max_, z2);
	}

	Value compression() const {
		return compression_;
	}

	void add(Value x) {
		add(x, 1);
	}

	inline void compress() {
		process();
	}

	// add a single centroid to the unprocessed vector, processing previously unprocessed sorted if our limit has
	// been reached.
	inline bool add(Value x, Weight w) {
		if (std::isnan(x)) {
			return false;
		}
		unprocessed_.push_back(Centroid(x, w));
		unprocessedWeight_ += w;
		processIfNecessary();
		return true;
	}

	inline void add(std::vector<Centroid>::const_iterator iter, std::vector<Centroid>::const_iterator end) {
		while (iter != end) {
			const size_t diff = std::distance(iter, end);
			const size_t room = maxUnprocessed_ - unprocessed_.size();
			auto mid = iter + std::min(diff, room);
			while (iter != mid) {
				unprocessed_.push_back(*(iter++));
			}
			if (unprocessed_.size() >= maxUnprocessed_) {
				process();
			}
		}
	}

private:
	Value compression_;

	Value min_ = std::numeric_limits<Value>::max();

	Value max_ = std::numeric_limits<Value>::min();

	Index maxProcessed_;

	Index maxUnprocessed_;

	Value processedWeight_ = 0.0;

	Value unprocessedWeight_ = 0.0;

	std::vector<Centroid> processed_;

	std::vector<Centroid> unprocessed_;

	std::vector<Weight> cumulative_;

	// return mean of i-th centroid
	inline Value mean(int i) const noexcept {
		return processed_[i].mean();
	}

	// return weight of i-th centroid
	inline Weight weight(int i) const noexcept {
		return processed_[i].weight();
	}

	// append all unprocessed centroids into current unprocessed vector
	void mergeUnprocessed(const std::vector<const TDigest *> &tdigests) {
		if (tdigests.size() == 0) {
			return;
		}

		size_t total = unprocessed_.size();
		for (auto &td : tdigests) {
			total += td->unprocessed_.size();
		}

		unprocessed_.reserve(total);
		for (auto &td : tdigests) {
			unprocessed_.insert(unprocessed_.end(), td->unprocessed_.cbegin(), td->unprocessed_.cend());
			unprocessedWeight_ += td->unprocessedWeight_;
		}
	}

	// merge all processed centroids together into a single sorted vector
	void mergeProcessed(const std::vector<const TDigest *> &tdigests) {
		if (tdigests.size() == 0) {
			return;
		}

		size_t total = 0;
		CentroidListQueue pq(CentroidListComparator {});
		for (auto &td : tdigests) {
			auto &sorted = td->processed_;
			auto size = sorted.size();
			if (size > 0) {
				pq.push(CentroidList(sorted));
				total += size;
				processedWeight_ += td->processedWeight_;
			}
		}
		if (total == 0) {
			return;
		}

		if (processed_.size() > 0) {
			pq.push(CentroidList(processed_));
			total += processed_.size();
		}

		std::vector<Centroid> sorted;
		sorted.reserve(total);

		while (!pq.empty()) {
			auto best = pq.top();
			pq.pop();
			sorted.push_back(*(best.iter));
			if (best.advance()) {
				pq.push(best);
			}
		}
		processed_ = std::move(sorted);
		if (processed_.size() > 0) {
			min_ = std::min(min_, processed_[0].mean());
			max_ = std::max(max_, (processed_.cend() - 1)->mean());
		}
	}

	inline void processIfNecessary() {
		if (isDirty()) {
			process();
		}
	}

	void updateCumulative() {
		const auto n = processed_.size();
		cumulative_.clear();
		cumulative_.reserve(n + 1);
		auto previous = 0.0;
		for (Index i = 0; i < n; i++) {
			auto current = weight(i);
			auto halfCurrent = current / 2.0;
			cumulative_.push_back(previous + halfCurrent);
			previous = previous + current;
		}
		cumulative_.push_back(previous);
	}

	// merges unprocessed_ centroids and processed_ centroids together and processes them
	// when complete, unprocessed_ will be empty and processed_ will have at most maxProcessed_ centroids
	inline void process() {
		CentroidComparator cc;
		std::sort(unprocessed_.begin(), unprocessed_.end(), cc);
		auto count = unprocessed_.size();
		unprocessed_.insert(unprocessed_.end(), processed_.cbegin(), processed_.cend());
		std::inplace_merge(unprocessed_.begin(), unprocessed_.begin() + count, unprocessed_.end(), cc);

		processedWeight_ += unprocessedWeight_;
		unprocessedWeight_ = 0;
		processed_.clear();

		processed_.push_back(unprocessed_[0]);
		Weight wSoFar = unprocessed_[0].weight();
		Weight wLimit = processedWeight_ * integratedQ(1.0);

		auto end = unprocessed_.end();
		for (auto iter = unprocessed_.cbegin() + 1; iter < end; iter++) {
			auto &centroid = *iter;
			Weight projectedW = wSoFar + centroid.weight();
			if (projectedW <= wLimit) {
				wSoFar = projectedW;
				(processed_.end() - 1)->add(centroid);
			} else {
				auto k1 = integratedLocation(wSoFar / processedWeight_);
				wLimit = processedWeight_ * integratedQ(k1 + 1.0);
				wSoFar += centroid.weight();
				processed_.emplace_back(centroid);
			}
		}
		unprocessed_.clear();
		min_ = std::min(min_, processed_[0].mean());
		max_ = std::max(max_, (processed_.cend() - 1)->mean());
		updateCumulative();
	}

	inline int checkWeights() {
		return checkWeights(processed_, processedWeight_);
	}

	size_t checkWeights(const std::vector<Centroid> &sorted, Value total) {
		size_t badWeight = 0;
		auto k1 = 0.0;
		auto q = 0.0;
		for (auto iter = sorted.cbegin(); iter != sorted.cend(); iter++) {
			auto w = iter->weight();
			auto dq = w / total;
			auto k2 = integratedLocation(q + dq);
			if (k2 - k1 > 1 && w != 1) {
				badWeight++;
			}
			if (k2 - k1 > 1.5 && w != 1) {
				badWeight++;
			}
			q += dq;
			k1 = k2;
		}

		return badWeight;
	}

	/**
	 * Converts a quantile into a centroid scale value.  The centroid scale is nomin_ally
	 * the number k of the centroid that a quantile point q should belong to.  Due to
	 * round-offs, however, we can't align things perfectly without splitting points
	 * and sorted.  We don't want to do that, so we have to allow for offsets.
	 * In the end, the criterion is that any quantile range that spans a centroid
	 * scale range more than one should be split across more than one centroid if
	 * possible.  This won't be possible if the quantile range refers to a single point
	 * or an already existing centroid.
	 * <p/>
	 * This mapping is steep near q=0 or q=1 so each centroid there will correspond to
	 * less q range.  Near q=0.5, the mapping is flatter so that sorted there will
	 * represent a larger chunk of quantiles.
	 *
	 * @param q The quantile scale value to be mapped.
	 * @return The centroid scale value corresponding to q.
	 */
	inline Value integratedLocation(Value q) const {
		return compression_ * (std::asin(2.0 * q - 1.0) + pi / 2) / pi;
	}

	inline Value integratedQ(Value k) const {
		return (std::sin(std::min(k, compression_) * pi / compression_ - pi / 2) + 1) / 2;
	}

	/**
	 * Same as {@link #weightedAverageSorted(Value, Value, Value, Value)} but flips
	 * the order of the variables if <code>x2</code> is greater than
	 * <code>x1</code>.
	 */
	static Value weightedAverage(Value x1, Value w1, Value x2, Value w2) {
		return (x1 <= x2) ? weightedAverageSorted(x1, w1, x2, w2) : weightedAverageSorted(x2, w2, x1, w1);
	}

	/**
	 * Compute the weighted average between <code>x1</code> with a weight of
	 * <code>w1</code> and <code>x2</code> with a weight of <code>w2</code>.
	 * This expects <code>x1</code> to be less than or equal to <code>x2</code>
	 * and is guaranteed to return a number between <code>x1</code> and
	 * <code>x2</code>.
	 */
	static Value weightedAverageSorted(Value x1, Value w1, Value x2, Value w2) {
		const Value x = (x1 * w1 + x2 * w2) / (w1 + w2);
		return std::max(x1, std::min(x, x2));
	}

	static Value interpolate(Value x, Value x0, Value x1) {
		return (x - x0) / (x1 - x0);
	}

	/**
	 * Computes an interpolated value of a quantile that is between two sorted.
	 *
	 * Index is the quantile desired multiplied by the total number of samples - 1.
	 *
	 * @param index              Denormalized quantile desired
	 * @param previousIndex      The denormalized quantile corresponding to the center of the previous centroid.
	 * @param nextIndex          The denormalized quantile corresponding to the center of the following centroid.
	 * @param previousMean       The mean of the previous centroid.
	 * @param nextMean           The mean of the following centroid.
	 * @return  The interpolated mean.
	 */
	static Value quantile(Value index, Value previousIndex, Value nextIndex, Value previousMean, Value nextMean) {
		const auto delta = nextIndex - previousIndex;
		const auto previousWeight = (nextIndex - index) / delta;
		const auto nextWeight = (index - previousIndex) / delta;
		return previousMean * previousWeight + nextMean * nextWeight;
	}
};

} // namespace tdigest


// LICENSE_CHANGE_END
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/operator/abs.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct AbsOperator {
	template <class TA, class TR>
	static inline TR Operation(TA input) {
		return input < 0 ? -input : input;
	}
};

template <>
inline hugeint_t AbsOperator::Operation(hugeint_t input) {
	const hugeint_t zero(0);
	return (input < zero) ? -input : input;
}

struct TryAbsOperator {
	template <class TA, class TR>
	static inline TR Operation(TA input) {
		return AbsOperator::Operation<TA, TR>(input);
	}
};

template <>
inline int8_t TryAbsOperator::Operation(int8_t input) {
	if (input == NumericLimits<int8_t>::Minimum()) {
		throw OutOfRangeException("Overflow on abs(%d)", input);
	}
	return input < 0 ? -input : input;
}

template <>
inline int16_t TryAbsOperator::Operation(int16_t input) {
	if (input == NumericLimits<int16_t>::Minimum()) {
		throw OutOfRangeException("Overflow on abs(%d)", input);
	}
	return input < 0 ? -input : input;
}

template <>
inline int32_t TryAbsOperator::Operation(int32_t input) {
	if (input == NumericLimits<int32_t>::Minimum()) {
		throw OutOfRangeException("Overflow on abs(%d)", input);
	}
	return input < 0 ? -input : input;
}

template <>
inline int64_t TryAbsOperator::Operation(int64_t input) {
	if (input == NumericLimits<int64_t>::Minimum()) {
		throw OutOfRangeException("Overflow on abs(%d)", input);
	}
	return input < 0 ? -input : input;
}

template <>
inline dtime_t TryAbsOperator::Operation(dtime_t input) {
	return dtime_t(TryAbsOperator::Operation<int64_t, int64_t>(input.micros));
}

template <>
inline interval_t TryAbsOperator::Operation(interval_t input) {
	return {TryAbsOperator::Operation<int32_t, int32_t>(input.months),
	        TryAbsOperator::Operation<int32_t, int32_t>(input.days),
	        TryAbsOperator::Operation<int64_t, int64_t>(input.micros)};
}

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/nested_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct ListFun {
	static void RegisterFunction(BuiltinFunctions &set);
};
struct HistogramFun {
	static void RegisterFunction(BuiltinFunctions &set);
	static AggregateFunction GetHistogramUnorderedMap(LogicalType &type);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/regression_functions.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
struct RegrAvgxFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrAvgyFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrCountFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrSlopeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrR2Fun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrSXXFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrSYYFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrSXYFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RegrInterceptFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/aggregate/regression/regr_count.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

struct RegrCountFunction {
	template <class STATE>
	static void Initialize(STATE *state) {
		*state = 0;
	}

	template <class STATE, class OP>
	static void Combine(const STATE &source, STATE *target, AggregateInputData &) {
		*target += source;
	}

	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		target[idx] = *state;
	}
	static bool IgnoreNull() {
		return true;
	}
	template <class A_TYPE, class B_TYPE, class STATE, class OP>
	static void Operation(STATE *state, AggregateInputData &, A_TYPE *x_data, B_TYPE *y_data, ValidityMask &amask,
	                      ValidityMask &bmask, idx_t xidx, idx_t yidx) {
		*state += 1;
	}
};

} // namespace duckdb
// REGR_SLOPE(y, x)
// Returns the slope of the linear regression line for non-null pairs in a group.
// It is computed for non-null pairs using the following formula:
// COVAR_POP(x,y) / VAR_POP(x)

//! Input : Any numeric type
//! Output : Double





namespace duckdb {

struct RegrSlopeState {
	CovarState cov_pop;
	StddevState var_pop;
};

struct RegrSlopeOperation {
	template <class STATE>
	static void Initialize(STATE *state) {
		CovarOperation::Initialize<CovarState>(&state->cov_pop);
		STDDevBaseOperation::Initialize<StddevState>(&state->var_pop);
	}

	template <class A_TYPE, class B_TYPE, class STATE, class OP>
	static void Operation(STATE *state, AggregateInputData &aggr_input_data, A_TYPE *x_data, B_TYPE *y_data,
	                      ValidityMask &amask, ValidityMask &bmask, idx_t xidx, idx_t yidx) {
		CovarOperation::Operation<A_TYPE, B_TYPE, CovarState, OP>(&state->cov_pop, aggr_input_data, y_data, x_data,
		                                                          bmask, amask, yidx, xidx);
		STDDevBaseOperation::Operation<A_TYPE, StddevState, OP>(&state->var_pop, aggr_input_data, y_data, bmask, yidx);
	}

	template <class STATE, class OP>
	static void Combine(const STATE &source, STATE *target, AggregateInputData &aggr_input_data) {
		CovarOperation::Combine<CovarState, OP>(source.cov_pop, &target->cov_pop, aggr_input_data);
		STDDevBaseOperation::Combine<StddevState, OP>(source.var_pop, &target->var_pop, aggr_input_data);
	}

	template <class T, class STATE>
	static void Finalize(Vector &result, AggregateInputData &, STATE *state, T *target, ValidityMask &mask, idx_t idx) {
		if (state->cov_pop.count == 0 || state->var_pop.count == 0) {
			mask.SetInvalid(idx);
		} else {
			auto cov = state->cov_pop.co_moment / state->cov_pop.count;
			auto var_pop = state->var_pop.count > 1 ? (state->var_pop.dsquared / state->var_pop.count) : 0;
			if (!Value::DoubleIsFinite(var_pop)) {
				throw OutOfRangeException("VARPOP is out of range!");
			}
			if (var_pop == 0) {
				mask.SetInvalid(idx);
				return;
			}
			target[idx] = cov / var_pop;
		}
	}

	static bool IgnoreNull() {
		return true;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/cast_rules.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
//! Contains a list of rules for casting
class CastRules {
public:
	//! Returns the cost of performing an implicit cost from "from" to "to", or -1 if an implicit cast is not possible
	static int64_t ImplicitCast(const LogicalType &from, const LogicalType &to);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/compression/compression.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct ConstantFun {
	static CompressionFunction GetFunction(PhysicalType type);
	static bool TypeIsSupported(PhysicalType type);
};

struct UncompressedFun {
	static CompressionFunction GetFunction(PhysicalType type);
	static bool TypeIsSupported(PhysicalType type);
};

struct RLEFun {
	static CompressionFunction GetFunction(PhysicalType type);
	static bool TypeIsSupported(PhysicalType type);
};

struct BitpackingFun {
	static CompressionFunction GetFunction(PhysicalType type);
	static bool TypeIsSupported(PhysicalType type);
};

struct DictionaryCompressionFun {
	static CompressionFunction GetFunction(PhysicalType type);
	static bool TypeIsSupported(PhysicalType type);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/pragma/pragma_functions.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct PragmaQueries {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaFunctions {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/blob_functions.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct Base64Fun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct EncodeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/date_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct AgeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DateDiffFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DatePartFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DateSubFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DateTruncFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CurrentTimeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CurrentDateFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CurrentTimestampFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct EpochFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MakeDateFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StrfTimeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StrpTimeFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ToIntervalFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/vector_operations/senary_executor.hpp
//
//
//===----------------------------------------------------------------------===//





#include <functional>

namespace duckdb {

struct SenaryExecutor {
	static const size_t NCOLS = 6;

	template <class TA, class TB, class TC, class TD, class TE, class TF, class TR,
	          class FUN = std::function<TR(TA, TB, TC, TD, TE, TF)>>
	static void Execute(DataChunk &input, Vector &result, FUN fun) {
		D_ASSERT(input.ColumnCount() >= NCOLS);
		const auto count = input.size();

		bool all_constant = true;
		bool any_null = false;
		for (const auto &v : input.data) {
			if (v.GetVectorType() == VectorType::CONSTANT_VECTOR) {
				if (ConstantVector::IsNull(v)) {
					any_null = true;
				}
			} else {
				all_constant = false;
				break;
			}
		}

		if (all_constant) {
			result.SetVectorType(VectorType::CONSTANT_VECTOR);
			if (any_null) {
				ConstantVector::SetNull(result, true);
			} else {
				auto adata = ConstantVector::GetData<TA>(input.data[0]);
				auto bdata = ConstantVector::GetData<TB>(input.data[1]);
				auto cdata = ConstantVector::GetData<TC>(input.data[2]);
				auto ddata = ConstantVector::GetData<TD>(input.data[3]);
				auto edata = ConstantVector::GetData<TE>(input.data[4]);
				auto fdata = ConstantVector::GetData<TF>(input.data[5]);
				auto result_data = ConstantVector::GetData<TR>(result);
				result_data[0] = fun(*adata, *bdata, *cdata, *ddata, *edata, *fdata);
			}
		} else {
			result.SetVectorType(VectorType::FLAT_VECTOR);
			auto result_data = FlatVector::GetData<TR>(result);
			auto &result_validity = FlatVector::Validity(result);

			bool all_valid = true;
			vector<VectorData> vdata(NCOLS);
			for (size_t c = 0; c < NCOLS; ++c) {
				input.data[c].Orrify(count, vdata[c]);
				all_valid = all_valid && vdata[c].validity.AllValid();
			}

			auto adata = (const TA *)(vdata[0].data);
			auto bdata = (const TB *)(vdata[1].data);
			auto cdata = (const TC *)(vdata[2].data);
			auto ddata = (const TD *)(vdata[3].data);
			auto edata = (const TE *)(vdata[4].data);
			auto fdata = (const TF *)(vdata[5].data);

			vector<idx_t> idx(NCOLS);
			if (all_valid) {
				for (idx_t r = 0; r < count; ++r) {
					for (size_t c = 0; c < NCOLS; ++c) {
						idx[c] = vdata[c].sel->get_index(r);
					}
					result_data[r] =
					    fun(adata[idx[0]], bdata[idx[1]], cdata[idx[2]], ddata[idx[3]], edata[idx[4]], fdata[idx[5]]);
				}
			} else {
				for (idx_t r = 0; r < count; ++r) {
					all_valid = true;
					for (size_t c = 0; c < NCOLS; ++c) {
						idx[c] = vdata[c].sel->get_index(r);
						if (!vdata[c].validity.RowIsValid(idx[c])) {
							result_validity.SetInvalid(r);
							all_valid = false;
							break;
						}
					}
					if (all_valid) {
						result_data[r] = fun(adata[idx[0]], bdata[idx[1]], cdata[idx[2]], ddata[idx[3]], edata[idx[4]],
						                     fdata[idx[5]]);
					}
				}
			}
		}
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/enum_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct EnumFirst {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct EnumLast {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct EnumRange {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct EnumRangeBoundary {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/generic_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class BoundFunctionExpression;

struct AliasFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct HashFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LeastFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct GreatestFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct StatsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct TypeOfFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ConstantOrNull {
	static ScalarFunction GetFunction(LogicalType return_type);
	static unique_ptr<FunctionData> Bind(Value value);
	static bool IsConstantOrNull(BoundFunctionExpression &expr, const Value &val);
};

struct CurrentSettingFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SystemFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ExportAggregateFunctionBindData : public FunctionData {
	unique_ptr<BoundAggregateExpression> aggregate;
	explicit ExportAggregateFunctionBindData(unique_ptr<Expression> aggregate_p);
	unique_ptr<FunctionData> Copy() const override;
	bool Equals(const FunctionData &other_p) const override;
};

struct ExportAggregateFunction {
	static unique_ptr<BoundAggregateExpression> Bind(unique_ptr<BoundAggregateExpression> child_aggregate);
	static ScalarFunction GetCombine();
	static ScalarFunction GetFinalize();
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/list_statistics.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Value;

class ListStatistics : public BaseStatistics {
public:
	explicit ListStatistics(LogicalType type);

	unique_ptr<BaseStatistics> child_stats;

public:
	void Merge(const BaseStatistics &other) override;
	FilterPropagateResult CheckZonemap(ExpressionType comparison_type, const Value &constant) const;

	unique_ptr<BaseStatistics> Copy() const override;
	void Serialize(FieldWriter &serializer) const override;
	static unique_ptr<BaseStatistics> Deserialize(FieldReader &source, LogicalType type);
	void Verify(Vector &vector, const SelectionVector &sel, idx_t count) const override;

	string ToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression_map.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct ValueHashFunction {
	uint64_t operator()(const Value &value) const {
		return (uint64_t)value.Hash();
	}
};

struct ValueEquality {
	bool operator()(const Value &a, const Value &b) const {
		return Value::NotDistinctFrom(a, b);
	}
};

template <typename T>
using value_map_t = unordered_map<Value, T, ValueHashFunction, ValueEquality>;

using value_set_t = unordered_set<Value, ValueHashFunction, ValueEquality>;

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/math_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct AbsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SignFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CeilFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct FloorFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RoundFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DegreesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RadiansFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RandomFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SetseedFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CbrtFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ExpFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct Log2Fun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct Log10Fun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LnFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PowFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SqrtFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PiFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct BitCountFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct GammaFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LogGammaFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct FactorialFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct NextAfterFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct EvenFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct IsNanFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct IsInfiniteFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct IsFiniteFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/trigonometric_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct SinFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CosFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct TanFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct AsinFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct AcosFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct AtanFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CotFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct Atan2Fun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/uuid_functions.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct UUIDFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/operators.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct AddFun {
	static ScalarFunction GetFunction(const LogicalType &type);
	static ScalarFunction GetFunction(const LogicalType &left_type, const LogicalType &right_type);
	static void RegisterFunction(BuiltinFunctions &set);
};

struct SubtractFun {
	static ScalarFunction GetFunction(const LogicalType &type);
	static ScalarFunction GetFunction(const LogicalType &left_type, const LogicalType &right_type);
	static void RegisterFunction(BuiltinFunctions &set);
};

struct MultiplyFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DivideFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ModFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct LeftShiftFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RightShiftFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct BitwiseAndFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct BitwiseOrFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct BitwiseXorFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct BitwiseNotFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/sequence_functions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct NextvalFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct CurrvalFun {
	static void RegisterFunction(BuiltinFunctions &set);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/scalar/regexp.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

struct RegexpMatchesBindData : public FunctionData {
	RegexpMatchesBindData(duckdb_re2::RE2::Options options, string constant_string);
	~RegexpMatchesBindData() override;

	duckdb_re2::RE2::Options options;
	string constant_string;
	bool constant_pattern;
	string range_min;
	string range_max;
	bool range_success;

	unique_ptr<FunctionData> Copy() const override;
	bool Equals(const FunctionData &other_p) const override;
};

struct RegexpReplaceBindData : public FunctionData {
	duckdb_re2::RE2::Options options;
	bool global_replace;

	unique_ptr<FunctionData> Copy() const override;
	bool Equals(const FunctionData &other_p) const override;
};

struct RegexpExtractBindData : public FunctionData {
	RegexpExtractBindData(bool constant_pattern, const string &pattern, const string &group_string_p);

	const bool constant_pattern;
	const string constant_string;

	const string group_string;
	const duckdb_re2::StringPiece rewrite;

	unique_ptr<FunctionData> Copy() const override;
	bool Equals(const FunctionData &other_p) const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/struct_statistics.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Value;

class StructStatistics : public BaseStatistics {
public:
	explicit StructStatistics(LogicalType type);

	vector<unique_ptr<BaseStatistics>> child_stats;

public:
	void Merge(const BaseStatistics &other) override;
	FilterPropagateResult CheckZonemap(ExpressionType comparison_type, const Value &constant) const;

	unique_ptr<BaseStatistics> Copy() const override;
	void Serialize(FieldWriter &writer) const override;
	static unique_ptr<BaseStatistics> Deserialize(FieldReader &reader, LogicalType type);
	void Verify(Vector &vector, const SelectionVector &sel, idx_t count) const override;

	string ToString() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table/arrow.hpp
//
//
//===----------------------------------------------------------------------===//








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



#include <thread>

namespace duckdb {
using std::thread;
}



namespace duckdb {
//===--------------------------------------------------------------------===//
// Arrow Variable Size Types
//===--------------------------------------------------------------------===//
enum class ArrowVariableSizeType : uint8_t { FIXED_SIZE = 0, NORMAL = 1, SUPER_SIZE = 2 };

//===--------------------------------------------------------------------===//
// Arrow Time/Date Types
//===--------------------------------------------------------------------===//
enum class ArrowDateTimeType : uint8_t {
	MILLISECONDS = 0,
	MICROSECONDS = 1,
	NANOSECONDS = 2,
	SECONDS = 3,
	DAYS = 4,
	MONTHS = 5
};

struct ArrowConvertData {
	ArrowConvertData(LogicalType type) : dictionary_type(type) {};
	ArrowConvertData() {};
	//! Hold type of dictionary
	LogicalType dictionary_type;
	//! If its a variable size type (e.g., strings, blobs, lists) holds which type it is
	vector<pair<ArrowVariableSizeType, idx_t>> variable_sz_type;
	//! If this is a date/time holds its precision
	vector<ArrowDateTimeType> date_time_precision;
};

typedef unique_ptr<ArrowArrayStreamWrapper> (*stream_factory_produce_t)(
    uintptr_t stream_factory_ptr, pair<unordered_map<idx_t, string>, vector<string>> &project_columns,
    TableFilterSet *filters);
typedef void (*stream_factory_get_schema_t)(uintptr_t stream_factory_ptr, ArrowSchemaWrapper &schema);

struct ArrowScanFunctionData : public PyTableFunctionData {
	ArrowScanFunctionData(idx_t rows_per_thread_p, stream_factory_produce_t scanner_producer_p,
	                      uintptr_t stream_factory_ptr_p)
	    : lines_read(0), rows_per_thread(rows_per_thread_p), stream_factory_ptr(stream_factory_ptr_p),
	      scanner_producer(scanner_producer_p), number_of_rows(0) {
	}
	//! This holds the original list type (col_idx, [ArrowListType,size])
	unordered_map<idx_t, unique_ptr<ArrowConvertData>> arrow_convert_data;
	atomic<idx_t> lines_read;
	ArrowSchemaWrapper schema_root;
	idx_t rows_per_thread;
	//! Pointer to the scanner factory
	uintptr_t stream_factory_ptr;
	//! Pointer to the scanner factory produce
	stream_factory_produce_t scanner_producer;
	//! Number of rows (Used in cardinality and progress bar)
	int64_t number_of_rows;
};

struct ArrowScanLocalState : public LocalTableFunctionState {
	explicit ArrowScanLocalState(unique_ptr<ArrowArrayWrapper> current_chunk) : chunk(move(current_chunk)) {
	}

	unique_ptr<ArrowArrayStreamWrapper> stream;
	shared_ptr<ArrowArrayWrapper> chunk;
	idx_t chunk_offset = 0;
	vector<column_t> column_ids;
	//! Store child vectors for Arrow Dictionary Vectors (col-idx,vector)
	unordered_map<idx_t, unique_ptr<Vector>> arrow_dictionary_vectors;
	TableFilterSet *filters = nullptr;
};

struct ArrowScanGlobalState : public GlobalTableFunctionState {
	unique_ptr<ArrowArrayStreamWrapper> stream;
	mutex main_mutex;
	bool ready = false;
	idx_t max_threads = 1;

	idx_t MaxThreads() const override {
		return max_threads;
	}
};

struct ArrowTableFunction {
public:
	static void RegisterFunction(BuiltinFunctions &set);

private:
	//! Binds an arrow table
	static unique_ptr<FunctionData> ArrowScanBind(ClientContext &context, TableFunctionBindInput &input,
	                                              vector<LogicalType> &return_types, vector<string> &names);
	//! Actual conversion from Arrow to DuckDB
	static void ArrowToDuckDB(ArrowScanLocalState &scan_state,
	                          std::unordered_map<idx_t, unique_ptr<ArrowConvertData>> &arrow_convert_data,
	                          DataChunk &output, idx_t start);

	//! Initialize Global State
	static unique_ptr<GlobalTableFunctionState> ArrowScanInitGlobal(ClientContext &context,
	                                                                TableFunctionInitInput &input);

	//! Initialize Local State
	static unique_ptr<LocalTableFunctionState> ArrowScanInitLocal(ExecutionContext &context,
	                                                              TableFunctionInitInput &input,
	                                                              GlobalTableFunctionState *global_state);

	//! Scan Function
	static void ArrowScanFunction(ClientContext &context, TableFunctionInput &data, DataChunk &output);

	//! Defines Maximum Number of Threads
	static idx_t ArrowScanMaxThreads(ClientContext &context, const FunctionData *bind_data);

	//! -----Utility Functions:-----
	//! Gets Arrow Table's Cardinality
	static unique_ptr<NodeStatistics> ArrowScanCardinality(ClientContext &context, const FunctionData *bind_data);
	//! Gets the progress on the table scan, used for Progress Bars
	static double ArrowProgress(ClientContext &context, const FunctionData *bind_data,
	                            const GlobalTableFunctionState *global_state);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table/range.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct CheckpointFunction {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct GlobTableFunction {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RangeTableFunction {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct RepeatTableFunction {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct UnnestTableFunction {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table/read_csv.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

struct BaseCSVData : public TableFunctionData {
	//! The file path of the CSV file to read or write
	vector<string> files;
	//! The CSV reader options
	BufferedCSVReaderOptions options;

	void Finalize();
};

struct WriteCSVData : public BaseCSVData {
	WriteCSVData(string file_path, vector<LogicalType> sql_types, vector<string> names) : sql_types(move(sql_types)) {
		files.push_back(move(file_path));
		options.names = move(names);
	}

	//! The SQL types to write
	vector<LogicalType> sql_types;
	//! The newline string to write
	string newline = "\n";
	//! Whether or not we are writing a simple CSV (delimiter, quote and escape are all 1 byte in length)
	bool is_simple;
	//! The size of the CSV file (in bytes) that we buffer before we flush it to disk
	idx_t flush_size = 4096 * 8;
};

struct ReadCSVData : public BaseCSVData {
	//! The expected SQL types to read
	vector<LogicalType> sql_types;
	//! The initial reader (if any): this is used when automatic detection is used during binding.
	//! In this case, the CSV reader is already created and might as well be re-used.
	unique_ptr<BufferedCSVReader> initial_reader;
};

struct CSVCopyFunction {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct ReadCSVTableFunction {
	static TableFunction GetFunction();
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table/system_functions.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct PragmaCollations {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaFunctionPragma {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaTableInfo {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaStorageInfo {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaLastProfilingOutput {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaDetailedProfilingOutput {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaVersion {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaDatabaseList {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct PragmaDatabaseSize {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBSchemasFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBColumnsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBConstraintsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBDependenciesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBExtensionsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBFunctionsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBKeywordsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBIndexesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBSequencesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBSettingsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBTablesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBTypesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct DuckDBViewsFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

struct TestType {
	TestType(LogicalType type_p, string name_p)
	    : type(move(type_p)), name(move(name_p)), min_value(Value::MinimumValue(type)),
	      max_value(Value::MaximumValue(type)) {
	}
	TestType(LogicalType type_p, string name_p, Value min, Value max)
	    : type(move(type_p)), name(move(name_p)), min_value(move(min)), max_value(move(max)) {
	}

	LogicalType type;
	string name;
	Value min_value;
	Value max_value;
};

struct TestAllTypesFun {
	static void RegisterFunction(BuiltinFunctions &set);
	static vector<TestType> GetTestTypes();
};

struct TestVectorTypesFun {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/function/table/summary.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

struct SummaryTableFunction {
	static void RegisterFunction(BuiltinFunctions &set);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/query_node/select_node.hpp
//
//
//===----------------------------------------------------------------------===//









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





namespace duckdb {

//===----
enum class AggregateHandling : uint8_t {
	STANDARD_HANDLING,     // standard handling as in the SELECT clause
	NO_AGGREGATES_ALLOWED, // no aggregates allowed: any aggregates in this node will result in an error
	FORCE_AGGREGATES       // force aggregates: any non-aggregate select list entry will become a GROUP
};

} // namespace duckdb


namespace duckdb {

//! SelectNode represents a standard SELECT statement
class SelectNode : public QueryNode {
public:
	SelectNode();

	//! The projection list
	vector<unique_ptr<ParsedExpression>> select_list;
	//! The FROM clause
	unique_ptr<TableRef> from_table;
	//! The WHERE clause
	unique_ptr<ParsedExpression> where_clause;
	//! list of groups
	GroupByNode groups;
	//! HAVING clause
	unique_ptr<ParsedExpression> having;
	//! QUALIFY clause
	unique_ptr<ParsedExpression> qualify;
	//! Aggregate handling during binding
	AggregateHandling aggregate_handling;
	//! The SAMPLE clause
	unique_ptr<SampleOptions> sample;

	const vector<unique_ptr<ParsedExpression>> &GetSelectList() const override {
		return select_list;
	}

public:
	//! Convert the query node to a string
	string ToString() const override;

	bool Equals(const QueryNode *other) const override;
	//! Create a copy of this SelectNode
	unique_ptr<QueryNode> Copy() const override;

	//! Serializes a QueryNode to a stand-alone binary blob
	void Serialize(FieldWriter &writer) const override;
	//! Deserializes a blob back into a QueryNode
	static unique_ptr<QueryNode> Deserialize(FieldReader &reader);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/capi_internal.hpp
//
//
//===----------------------------------------------------------------------===//








#include <cstring>
#include <cassert>

#ifdef _WIN32
#ifndef strdup
#define strdup _strdup
#endif
#endif

namespace duckdb {

struct DatabaseData {
	unique_ptr<DuckDB> database;
};

struct PreparedStatementWrapper {
	unique_ptr<PreparedStatement> statement;
	vector<Value> values;
};

struct ArrowResultWrapper {
	unique_ptr<MaterializedQueryResult> result;
	unique_ptr<DataChunk> current_chunk;
	string timezone_config;
};

struct AppenderWrapper {
	unique_ptr<Appender> appender;
	string error;
};

enum class CAPIResultSetType : uint8_t {
	CAPI_RESULT_TYPE_NONE = 0,
	CAPI_RESULT_TYPE_MATERIALIZED,
	CAPI_RESULT_TYPE_DEPRECATED
};

struct DuckDBResultData {
	//! The underlying query result
	unique_ptr<QueryResult> result;
	// Results can only use either the new API or the old API, not a mix of the two
	// They start off as "none" and switch to one or the other when an API method is used
	CAPIResultSetType result_set_type;
};

duckdb_type ConvertCPPTypeToC(const LogicalType &type);
LogicalTypeId ConvertCTypeToCPP(duckdb_type c_type);
idx_t GetCTypeSize(duckdb_type type);
duckdb_state duckdb_translate_result(unique_ptr<QueryResult> result, duckdb_result *out);
bool deprecated_materialize_result(duckdb_result *result);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/client_context_file_opener.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class ClientContext;

//! ClientContext-specific FileOpener implemenation.
//! This object is owned by ClientContext and never outlives it.
class ClientContextFileOpener : public FileOpener {
public:
	explicit ClientContextFileOpener(ClientContext &context_p) : context(context_p) {
	}

	bool TryGetCurrentSetting(const string &key, Value &result) override;

private:
	ClientContext &context;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/optimizer.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/expression_rewriter.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/matcher/logical_operator_matcher.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The LogicalOperatorMatcher class contains a set of matchers that can be used to match LogicalOperators
class LogicalOperatorMatcher {
public:
	virtual ~LogicalOperatorMatcher() {
	}

	virtual bool Match(LogicalOperatorType type) = 0;
};

//! The SpecificLogicalTypeMatcher class matches only a single specified LogicalOperatorType
class SpecificLogicalTypeMatcher : public LogicalOperatorMatcher {
public:
	explicit SpecificLogicalTypeMatcher(LogicalOperatorType type) : type(type) {
	}

	bool Match(LogicalOperatorType type) override {
		return type == this->type;
	}

private:
	LogicalOperatorType type;
};

} // namespace duckdb


namespace duckdb {
class ExpressionRewriter;

class Rule {
public:
	explicit Rule(ExpressionRewriter &rewriter) : rewriter(rewriter) {
	}
	virtual ~Rule() {
	}

	//! The expression rewriter this rule belongs to
	ExpressionRewriter &rewriter;
	//! The root
	unique_ptr<LogicalOperatorMatcher> logical_root;
	//! The expression matcher of the rule
	unique_ptr<ExpressionMatcher> root;

	virtual unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &fixed_point,
	                                     bool is_root) = 0;
};

} // namespace duckdb




namespace duckdb {
class ClientContext;

//! The ExpressionRewriter performs a set of fixed rewrite rules on the expressions that occur in a SQL statement
class ExpressionRewriter : public LogicalOperatorVisitor {
public:
	explicit ExpressionRewriter(ClientContext &context) : context(context) {
	}

public:
	//! The set of rules as known by the Expression Rewriter
	vector<unique_ptr<Rule>> rules;

	ClientContext &context;

public:
	void VisitOperator(LogicalOperator &op) override;
	void VisitExpression(unique_ptr<Expression> *expression) override;

	// Generates either a constant_or_null(child) expression
	static unique_ptr<Expression> ConstantOrNull(unique_ptr<Expression> child, Value value);
	static unique_ptr<Expression> ConstantOrNull(vector<unique_ptr<Expression>> children, Value value);

private:
	//! Apply a set of rules to a specific expression
	static unique_ptr<Expression> ApplyRules(LogicalOperator &op, const vector<Rule *> &rules,
	                                         unique_ptr<Expression> expr, bool &changes_made, bool is_root = false);

	LogicalOperator *op;
	vector<Rule *> to_apply_rules;
};

} // namespace duckdb





#include <functional>

namespace duckdb {
class Binder;

class Optimizer {
public:
	Optimizer(Binder &binder, ClientContext &context);

	unique_ptr<LogicalOperator> Optimize(unique_ptr<LogicalOperator> plan);

	ClientContext &context;
	Binder &binder;
	ExpressionRewriter rewriter;

private:
	void RunOptimizer(OptimizerType type, const std::function<void()> &callback);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/drop_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class DropStatement : public SQLStatement {
public:
	DropStatement();

	unique_ptr<DropInfo> info;

protected:
	DropStatement(const DropStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/planner.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class ClientContext;
class PreparedStatementData;

//! The planner creates a logical query plan from the parsed SQL statements
//! using the Binder and LogicalPlanGenerator.
class Planner {
public:
	explicit Planner(ClientContext &context);

	void CreatePlan(unique_ptr<SQLStatement> statement);

	unique_ptr<LogicalOperator> plan;
	vector<string> names;
	vector<LogicalType> types;
	unordered_map<idx_t, vector<unique_ptr<Value>>> value_map;
	vector<LogicalType> parameter_types;

	shared_ptr<Binder> binder;
	ClientContext &context;

	StatementProperties properties;

private:
	void CreatePlan(SQLStatement &statement);
	shared_ptr<PreparedStatementData> PrepareSQLStatement(unique_ptr<SQLStatement> statement);
	void PlanPrepare(unique_ptr<SQLStatement> statement);
	void PlanExecute(unique_ptr<SQLStatement> statement);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/relation_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class RelationStatement : public SQLStatement {
public:
	explicit RelationStatement(shared_ptr<Relation> relation);

	shared_ptr<Relation> relation;

protected:
	RelationStatement(const RelationStatement &other) = default;

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/pragma_handler.hpp
//
//
//===----------------------------------------------------------------------===//





//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/pragma_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class PragmaStatement : public SQLStatement {
public:
	PragmaStatement();

	unique_ptr<PragmaInfo> info;

protected:
	PragmaStatement(const PragmaStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb


namespace duckdb {
class ClientContext;
class ClientContextLock;
class SQLStatement;
struct PragmaInfo;

//! Pragma handler is responsible for converting certain pragma statements into new queries
class PragmaHandler {
public:
	explicit PragmaHandler(ClientContext &context);

	void HandlePragmaStatements(ClientContextLock &lock, vector<unique_ptr<SQLStatement>> &statements);

private:
	ClientContext &context;

private:
	//! Handles a pragma statement, (potentially) returning a new statement to replace the current one
	string HandlePragma(SQLStatement *statement);

	void HandlePragmaStatementsInternal(vector<unique_ptr<SQLStatement>> &statements);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/settings.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ClientContext;
class DatabaseInstance;
struct DBConfig;

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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(ClientContext &context);
};

struct DebugManyFreeListBlocks {
	static constexpr const char *Name = "debug_many_free_list_blocks";
	static constexpr const char *Description = "DEBUG SETTING: add additional blocks to the free list";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BOOLEAN;
	static void SetGlobal(DatabaseInstance *db, DBConfig &config, const Value &parameter);
	static Value GetSetting(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 Value GetSetting(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 SetLocal(ClientContext &context, const Value &parameter);
	static Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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: empty string, queries are not logged)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::VARCHAR;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 (default: 12)";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static Value GetSetting(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 Value GetSetting(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 Value GetSetting(ClientContext &context);
};

struct ProfilerHistorySize {
	static constexpr const char *Name = "profiler_history_size";
	static constexpr const char *Description = "Sets the profiler history size";
	static constexpr const LogicalTypeId InputType = LogicalTypeId::BIGINT;
	static void SetLocal(ClientContext &context, const Value &parameter);
	static Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(ClientContext &context);
};

struct SearchPathSetting {
	static constexpr const char *Name = "search_path";
	static constexpr const char *Description =
	    "Sets the default search 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 Value GetSetting(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 Value GetSetting(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 Value GetSetting(ClientContext &context);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/query_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class SelectStatement;

class QueryRelation : public Relation {
public:
	QueryRelation(const std::shared_ptr<ClientContext> &context, unique_ptr<SelectStatement> select_stmt, string alias);
	~QueryRelation();

	unique_ptr<SelectStatement> select_stmt;
	string alias;
	vector<ColumnDefinition> columns;

public:
	static unique_ptr<SelectStatement> ParseStatement(ClientContext &context, const string &query, const string &error);
	unique_ptr<QueryNode> GetQueryNode() override;
	unique_ptr<TableRef> GetTableRef() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

private:
	unique_ptr<SelectStatement> GetSelectStatement();
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/read_csv_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class ReadCSVRelation : public Relation {
public:
	ReadCSVRelation(const std::shared_ptr<ClientContext> &context, string csv_file, vector<ColumnDefinition> columns,
	                bool auto_detect = false, string alias = string());

	string csv_file;
	bool auto_detect;
	string alias;
	vector<ColumnDefinition> columns;

public:
	unique_ptr<QueryNode> GetQueryNode() override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;
	unique_ptr<TableRef> GetTableRef() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/table_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class TableRelation : public Relation {
public:
	TableRelation(const std::shared_ptr<ClientContext> &context, unique_ptr<TableDescription> description);

	unique_ptr<TableDescription> description;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

	unique_ptr<TableRef> GetTableRef() override;

	void Update(const string &update, const string &condition = string()) override;
	void Delete(const string &condition = string()) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/table_function_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class TableFunctionRelation : public Relation {
public:
	TableFunctionRelation(const std::shared_ptr<ClientContext> &context, string name, vector<Value> parameters,
	                      named_parameter_map_t named_parameters, shared_ptr<Relation> input_relation_p = nullptr);

	TableFunctionRelation(const std::shared_ptr<ClientContext> &context, string name, vector<Value> parameters,
	                      shared_ptr<Relation> input_relation_p = nullptr);

	string name;
	vector<Value> parameters;
	named_parameter_map_t named_parameters;
	vector<ColumnDefinition> columns;
	shared_ptr<Relation> input_relation;

public:
	unique_ptr<QueryNode> GetQueryNode() override;
	unique_ptr<TableRef> GetTableRef() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/value_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class ValueRelation : public Relation {
public:
	ValueRelation(const std::shared_ptr<ClientContext> &context, const vector<vector<Value>> &values,
	              vector<string> names, string alias = "values");
	ValueRelation(const std::shared_ptr<ClientContext> &context, const string &values, vector<string> names,
	              string alias = "values");

	vector<vector<unique_ptr<ParsedExpression>>> expressions;
	vector<string> names;
	vector<ColumnDefinition> columns;
	string alias;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

	unique_ptr<TableRef> GetTableRef() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/view_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class ViewRelation : public Relation {
public:
	ViewRelation(const std::shared_ptr<ClientContext> &context, string schema_name, string view_name);

	string schema_name;
	string view_name;
	vector<ColumnDefinition> columns;

public:
	unique_ptr<QueryNode> GetQueryNode() override;
	unique_ptr<TableRef> GetTableRef() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/connection_manager.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
class ClientContext;
class DatabaseInstance;

class ConnectionManager {
public:
	ConnectionManager() {
	}

	void AddConnection(ClientContext &context) {
		lock_guard<mutex> lock(connections_lock);
		connections.insert(make_pair(&context, weak_ptr<ClientContext>(context.shared_from_this())));
	}

	void RemoveConnection(ClientContext &context) {
		lock_guard<mutex> lock(connections_lock);
		connections.erase(&context);
	}

	vector<shared_ptr<ClientContext>> GetConnectionList() {
		vector<shared_ptr<ClientContext>> result;
		for (auto &it : connections) {
			auto connection = it.second.lock();
			if (!connection) {
				connections.erase(it.first);
				continue;
			} else {
				result.push_back(move(connection));
			}
		}

		return result;
	}

	static ConnectionManager &Get(DatabaseInstance &db);
	static ConnectionManager &Get(ClientContext &context);

public:
	mutex connections_lock;
	unordered_map<ClientContext *, weak_ptr<ClientContext>> connections;
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #9
// See the end of this file for a list

// taken from: https://github.com/yhirose/cpp-httplib/blob/v0.10.2/httplib.h
// Note: some modifications are made to file


//
//  httplib.hpp
//
//  Copyright (c) 2021 Yuji Hirose. All rights reserved.
//  MIT License
//

#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H

/*
 * Configuration
 */
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
#define CPPHTTPLIB_NAMESPACE duckdb_httplib_openssl
#else
#define CPPHTTPLIB_NAMESPACE duckdb_httplib
#endif

#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
#endif

#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5
#endif

#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300
#endif

#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
#endif

#ifndef CPPHTTPLIB_READ_TIMEOUT_SECOND
#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5
#endif

#ifndef CPPHTTPLIB_READ_TIMEOUT_USECOND
#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0
#endif

#ifndef CPPHTTPLIB_WRITE_TIMEOUT_SECOND
#define CPPHTTPLIB_WRITE_TIMEOUT_SECOND 5
#endif

#ifndef CPPHTTPLIB_WRITE_TIMEOUT_USECOND
#define CPPHTTPLIB_WRITE_TIMEOUT_USECOND 0
#endif

#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND
#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0
#endif

#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND
#ifdef _WIN32
#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 10000
#else
#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0
#endif
#endif

#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
#endif

#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH
#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192
#endif

#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT
#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
#endif

#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits<size_t>::max)())
#endif

#ifndef CPPHTTPLIB_TCP_NODELAY
#define CPPHTTPLIB_TCP_NODELAY false
#endif

#ifndef CPPHTTPLIB_RECV_BUFSIZ
#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u)
#endif

#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
#endif

#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
#define CPPHTTPLIB_THREAD_POOL_COUNT                                           \
  ((std::max)(8u, std::thread::hardware_concurrency() > 0                      \
                      ? std::thread::hardware_concurrency() - 1                \
                      : 0))
#endif

#ifndef CPPHTTPLIB_RECV_FLAGS
#define CPPHTTPLIB_RECV_FLAGS 0
#endif

#ifndef CPPHTTPLIB_SEND_FLAGS
#define CPPHTTPLIB_SEND_FLAGS 0
#endif

#ifndef CPPHTTPLIB_LISTEN_BACKLOG
#define CPPHTTPLIB_LISTEN_BACKLOG 5
#endif

/*
 * Headers
 */

#ifdef _WIN32
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif //_CRT_SECURE_NO_WARNINGS

#ifndef _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#endif //_CRT_NONSTDC_NO_DEPRECATE

#if defined(_MSC_VER)
#ifdef _WIN64
using ssize_t = __int64;
#else
using ssize_t = int;
#endif

#if _MSC_VER < 1900
#define snprintf _snprintf_s
#endif
#endif // _MSC_VER

#ifndef S_ISREG
#define S_ISREG(m) (((m)&S_IFREG) == S_IFREG)
#endif // S_ISREG

#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR)
#endif // S_ISDIR

#ifndef NOMINMAX
#define NOMINMAX
#endif // NOMINMAX

#include <io.h>
#ifdef _WINSOCKAPI_
#undef _WINSOCKAPI_
#endif
#include <winsock2.h>

#include <wincrypt.h>
#include <ws2tcpip.h>

#ifndef WSA_FLAG_NO_HANDLE_INHERIT
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif

#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "cryptui.lib")
#endif

#ifndef strcasecmp
#define strcasecmp _stricmp
#endif // strcasecmp

using socket_t = SOCKET;
#ifdef CPPHTTPLIB_USE_POLL
#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
#endif

#else // not _WIN32

#include <arpa/inet.h>
#include <cstring>
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef __linux__
#include <resolv.h>
#endif
#include <netinet/tcp.h>
#ifdef CPPHTTPLIB_USE_POLL
#include <poll.h>
#endif
#include <csignal>
#include <pthread.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>

using socket_t = int;
#ifndef INVALID_SOCKET
#define INVALID_SOCKET (-1)
#endif
#endif //_WIN32

#include <algorithm>
#include <array>
#include <atomic>
#include <cassert>
#include <cctype>
#include <climits>
#include <condition_variable>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <sys/stat.h>
#include <thread>



#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
// these are defined in wincrypt.h and it breaks compilation if BoringSSL is
// used
#ifdef _WIN32
#undef X509_NAME
#undef X509_CERT_PAIR
#undef X509_EXTENSIONS
#undef PKCS7_SIGNER_INFO
#endif

#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>

#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)
#include <openssl/applink.c>
#endif

#include <iostream>
#include <sstream>

// Disabled OpenSSL version check for CI
//#if OPENSSL_VERSION_NUMBER < 0x1010100fL
//#error Sorry, OpenSSL versions prior to 1.1.1 are not supported
//#endif

#if OPENSSL_VERSION_NUMBER < 0x10100000L
#include <openssl/crypto.h>
inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) {
	return M_ASN1_STRING_data(asn1);
}
#endif
#endif

#ifdef CPPHTTPLIB_ZLIB_SUPPORT
#include <zlib.h>
#endif

#ifdef CPPHTTPLIB_BROTLI_SUPPORT
#include <brotli/decode.h>
#include <brotli/encode.h>
#endif

/*
 * Declaration
 */
namespace CPPHTTPLIB_NAMESPACE {

namespace detail {

/*
 * Backport std::make_unique from C++14.
 *
 * NOTE: This code came up with the following stackoverflow post:
 * https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique
 *
 */

template <class T, class... Args>
typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(Args &&...args) {
	return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template <class T>
typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(std::size_t n) {
	typedef typename std::remove_extent<T>::type RT;
	return std::unique_ptr<T>(new RT[n]);
}

struct ci {
	bool operator()(const std::string &s1, const std::string &s2) const {
		return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(),
		                                    s2.end(),
		                                    [](unsigned char c1, unsigned char c2) {
			                                    return ::tolower(c1) < ::tolower(c2);
		                                    });
	}
};

} // namespace detail

using Headers = std::multimap<std::string, std::string, detail::ci>;

using Params = std::multimap<std::string, std::string>;
using Match = duckdb_re2::Match;
using Regex = duckdb_re2::Regex;

using Progress = std::function<bool(uint64_t current, uint64_t total)>;

struct Response;
using ResponseHandler = std::function<bool(const Response &response)>;

struct MultipartFormData {
	std::string name;
	std::string content;
	std::string filename;
	std::string content_type;
};
using MultipartFormDataItems = std::vector<MultipartFormData>;
using MultipartFormDataMap = std::multimap<std::string, MultipartFormData>;

class DataSink {
public:
	DataSink() : os(&sb_), sb_(*this) {}

	DataSink(const DataSink &) = delete;
	DataSink &operator=(const DataSink &) = delete;
	DataSink(DataSink &&) = delete;
	DataSink &operator=(DataSink &&) = delete;

	std::function<bool(const char *data, size_t data_len)> write;
	std::function<void()> done;
	std::function<bool()> is_writable;
	std::ostream os;

private:
	class data_sink_streambuf : public std::streambuf {
	public:
		explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}

	protected:
		std::streamsize xsputn(const char *s, std::streamsize n) {
			sink_.write(s, static_cast<size_t>(n));
			return n;
		}

	private:
		DataSink &sink_;
	};

	data_sink_streambuf sb_;
};

using ContentProvider =
    std::function<bool(size_t offset, size_t length, DataSink &sink)>;

using ContentProviderWithoutLength =
    std::function<bool(size_t offset, DataSink &sink)>;

using ContentProviderResourceReleaser = std::function<void(bool success)>;

using ContentReceiverWithProgress =
    std::function<bool(const char *data, size_t data_length, uint64_t offset,
                       uint64_t total_length)>;

using ContentReceiver =
    std::function<bool(const char *data, size_t data_length)>;

using MultipartContentHeader =
    std::function<bool(const MultipartFormData &file)>;

class ContentReader {
public:
	using Reader = std::function<bool(ContentReceiver receiver)>;
	using MultipartReader = std::function<bool(MultipartContentHeader header,
	                                           ContentReceiver receiver)>;

	ContentReader(Reader reader, MultipartReader multipart_reader)
	    : reader_(std::move(reader)),
	      multipart_reader_(std::move(multipart_reader)) {}

	bool operator()(MultipartContentHeader header,
	                ContentReceiver receiver) const {
		return multipart_reader_(std::move(header), std::move(receiver));
	}

	bool operator()(ContentReceiver receiver) const {
		return reader_(std::move(receiver));
	}

	Reader reader_;
	MultipartReader multipart_reader_;
};

using Range = std::pair<ssize_t, ssize_t>;
using Ranges = std::vector<Range>;

struct Request {
	std::string method;
	std::string path;
	Headers headers;
	std::string body;

	std::string remote_addr;
	int remote_port = -1;

	// for server
	std::string version;
	std::string target;
	Params params;
	MultipartFormDataMap files;
	Ranges ranges;
	Match matches;

	// for client
	ResponseHandler response_handler;
	ContentReceiverWithProgress content_receiver;
	Progress progress;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	const SSL *ssl = nullptr;
#endif

	bool has_header(const char *key) const;
	std::string get_header_value(const char *key, size_t id = 0) const;
	template <typename T>
	T get_header_value(const char *key, size_t id = 0) const;
	size_t get_header_value_count(const char *key) const;
	void set_header(const char *key, const char *val);
	void set_header(const char *key, const std::string &val);

	bool has_param(const char *key) const;
	std::string get_param_value(const char *key, size_t id = 0) const;
	size_t get_param_value_count(const char *key) const;

	bool is_multipart_form_data() const;

	bool has_file(const char *key) const;
	MultipartFormData get_file_value(const char *key) const;

	// private members...
	size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT;
	size_t content_length_ = 0;
	ContentProvider content_provider_;
	bool is_chunked_content_provider_ = false;
	size_t authorization_count_ = 0;
};

struct Response {
	std::string version;
	int status = -1;
	std::string reason;
	Headers headers;
	std::string body;
	std::string location; // Redirect location

	bool has_header(const char *key) const;
	std::string get_header_value(const char *key, size_t id = 0) const;
	template <typename T>
	T get_header_value(const char *key, size_t id = 0) const;
	size_t get_header_value_count(const char *key) const;
	void set_header(const char *key, const char *val);
	void set_header(const char *key, const std::string &val);

	void set_redirect(const char *url, int status = 302);
	void set_redirect(const std::string &url, int status = 302);
	void set_content(const char *s, size_t n, const char *content_type);
	void set_content(const std::string &s, const char *content_type);

	void set_content_provider(
	    size_t length, const char *content_type, ContentProvider provider,
	    ContentProviderResourceReleaser resource_releaser = nullptr);

	void set_content_provider(
	    const char *content_type, ContentProviderWithoutLength provider,
	    ContentProviderResourceReleaser resource_releaser = nullptr);

	void set_chunked_content_provider(
	    const char *content_type, ContentProviderWithoutLength provider,
	    ContentProviderResourceReleaser resource_releaser = nullptr);

	Response() = default;
	Response(const Response &) = default;
	Response &operator=(const Response &) = default;
	Response(Response &&) = default;
	Response &operator=(Response &&) = default;
	~Response() {
		if (content_provider_resource_releaser_) {
			content_provider_resource_releaser_(content_provider_success_);
		}
	}

	// private members...
	size_t content_length_ = 0;
	ContentProvider content_provider_;
	ContentProviderResourceReleaser content_provider_resource_releaser_;
	bool is_chunked_content_provider_ = false;
	bool content_provider_success_ = false;
};

class Stream {
public:
	virtual ~Stream() = default;

	virtual bool is_readable() const = 0;
	virtual bool is_writable() const = 0;

	virtual ssize_t read(char *ptr, size_t size) = 0;
	virtual ssize_t write(const char *ptr, size_t size) = 0;
	virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0;
	virtual socket_t socket() const = 0;

	template <typename... Args>
	ssize_t write_format(const char *fmt, const Args &...args);
	ssize_t write(const char *ptr);
	ssize_t write(const std::string &s);
};

class TaskQueue {
public:
	TaskQueue() = default;
	virtual ~TaskQueue() = default;

	virtual void enqueue(std::function<void()> fn) = 0;
	virtual void shutdown() = 0;

	virtual void on_idle() {}
};

class ThreadPool : public TaskQueue {
public:
	explicit ThreadPool(size_t n) : shutdown_(false) {
		while (n) {
			threads_.emplace_back(worker(*this));
			n--;
		}
	}

	ThreadPool(const ThreadPool &) = delete;
	~ThreadPool() override = default;

	void enqueue(std::function<void()> fn) override {
		std::unique_lock<std::mutex> lock(mutex_);
		jobs_.push_back(std::move(fn));
		cond_.notify_one();
	}

	void shutdown() override {
		// Stop all worker threads...
		{
			std::unique_lock<std::mutex> lock(mutex_);
			shutdown_ = true;
		}

		cond_.notify_all();

		// Join...
		for (auto &t : threads_) {
			t.join();
		}
	}

private:
	struct worker {
		explicit worker(ThreadPool &pool) : pool_(pool) {}

		void operator()() {
			for (;;) {
				std::function<void()> fn;
				{
					std::unique_lock<std::mutex> lock(pool_.mutex_);

					pool_.cond_.wait(
					    lock, [&] { return !pool_.jobs_.empty() || pool_.shutdown_; });

					if (pool_.shutdown_ && pool_.jobs_.empty()) { break; }

					fn = pool_.jobs_.front();
					pool_.jobs_.pop_front();
				}

				assert(true == static_cast<bool>(fn));
				fn();
			}
		}

		ThreadPool &pool_;
	};
	friend struct worker;

	std::vector<std::thread> threads_;
	std::list<std::function<void()>> jobs_;

	bool shutdown_;

	std::condition_variable cond_;
	std::mutex mutex_;
};

using Logger = std::function<void(const Request &, const Response &)>;

using SocketOptions = std::function<void(socket_t sock)>;

void default_socket_options(socket_t sock);

class Server {
public:
	using Handler = std::function<void(const Request &, Response &)>;

	using ExceptionHandler =
	    std::function<void(const Request &, Response &, std::exception &e)>;

	enum class HandlerResponse {
		Handled,
		Unhandled,
	};
	using HandlerWithResponse =
	    std::function<HandlerResponse(const Request &, Response &)>;

	using HandlerWithContentReader = std::function<void(
	    const Request &, Response &, const ContentReader &content_reader)>;

	using Expect100ContinueHandler =
	    std::function<int(const Request &, Response &)>;

	Server();

	virtual ~Server();

	virtual bool is_valid() const;

	Server &Get(const std::string &pattern, Handler handler);
	Server &Post(const std::string &pattern, Handler handler);
	Server &Post(const std::string &pattern, HandlerWithContentReader handler);
	Server &Put(const std::string &pattern, Handler handler);
	Server &Put(const std::string &pattern, HandlerWithContentReader handler);
	Server &Patch(const std::string &pattern, Handler handler);
	Server &Patch(const std::string &pattern, HandlerWithContentReader handler);
	Server &Delete(const std::string &pattern, Handler handler);
	Server &Delete(const std::string &pattern, HandlerWithContentReader handler);
	Server &Options(const std::string &pattern, Handler handler);

	bool set_base_dir(const std::string &dir,
	                  const std::string &mount_point = std::string());
	bool set_mount_point(const std::string &mount_point, const std::string &dir,
	                     Headers headers = Headers());
	bool remove_mount_point(const std::string &mount_point);
	Server &set_file_extension_and_mimetype_mapping(const char *ext,
	                                                const char *mime);
	Server &set_file_request_handler(Handler handler);

	Server &set_error_handler(HandlerWithResponse handler);
	Server &set_error_handler(Handler handler);
	Server &set_exception_handler(ExceptionHandler handler);
	Server &set_pre_routing_handler(HandlerWithResponse handler);
	Server &set_post_routing_handler(Handler handler);

	Server &set_expect_100_continue_handler(Expect100ContinueHandler handler);
	Server &set_logger(Logger logger);

	Server &set_address_family(int family);
	Server &set_tcp_nodelay(bool on);
	Server &set_socket_options(SocketOptions socket_options);

	Server &set_default_headers(Headers headers);

	Server &set_keep_alive_max_count(size_t count);
	Server &set_keep_alive_timeout(time_t sec);

	Server &set_read_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	Server &set_read_timeout(const std::chrono::duration<Rep, Period> &duration);

	Server &set_write_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	Server &set_write_timeout(const std::chrono::duration<Rep, Period> &duration);

	Server &set_idle_interval(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	Server &set_idle_interval(const std::chrono::duration<Rep, Period> &duration);

	Server &set_payload_max_length(size_t length);

	bool bind_to_port(const char *host, int port, int socket_flags = 0);
	int bind_to_any_port(const char *host, int socket_flags = 0);
	bool listen_after_bind();

	bool listen(const char *host, int port, int socket_flags = 0);

	bool is_running() const;
	void stop();

	std::function<TaskQueue *(void)> new_task_queue;

protected:
	bool process_request(Stream &strm, bool close_connection,
	                     bool &connection_closed,
	                     const std::function<void(Request &)> &setup_request);

	std::atomic<socket_t> svr_sock_;
	size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
	time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND;
	time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
	time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND;
	time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND;
	time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND;
	time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND;
	time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND;
	size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;

private:
	using Handlers = std::vector<std::pair<Regex, Handler>>;
	using HandlersForContentReader =
	    std::vector<std::pair<Regex, HandlerWithContentReader>>;

	socket_t create_server_socket(const char *host, int port, int socket_flags,
	                              SocketOptions socket_options) const;
	int bind_internal(const char *host, int port, int socket_flags);
	bool listen_internal();

	bool routing(Request &req, Response &res, Stream &strm);
	bool handle_file_request(const Request &req, Response &res,
	                         bool head = false);
	bool dispatch_request(Request &req, Response &res, const Handlers &handlers);
	bool
	dispatch_request_for_content_reader(Request &req, Response &res,
	                                    ContentReader content_reader,
	                                    const HandlersForContentReader &handlers);

	bool parse_request_line(const char *s, Request &req);
	void apply_ranges(const Request &req, Response &res,
	                  std::string &content_type, std::string &boundary);
	bool write_response(Stream &strm, bool close_connection, const Request &req,
	                    Response &res);
	bool write_response_with_content(Stream &strm, bool close_connection,
	                                 const Request &req, Response &res);
	bool write_response_core(Stream &strm, bool close_connection,
	                         const Request &req, Response &res,
	                         bool need_apply_ranges);
	bool write_content_with_provider(Stream &strm, const Request &req,
	                                 Response &res, const std::string &boundary,
	                                 const std::string &content_type);
	bool read_content(Stream &strm, Request &req, Response &res);
	bool
	read_content_with_content_receiver(Stream &strm, Request &req, Response &res,
	                                   ContentReceiver receiver,
	                                   MultipartContentHeader multipart_header,
	                                   ContentReceiver multipart_receiver);
	bool read_content_core(Stream &strm, Request &req, Response &res,
	                       ContentReceiver receiver,
	                       MultipartContentHeader mulitpart_header,
	                       ContentReceiver multipart_receiver);

	virtual bool process_and_close_socket(socket_t sock);

	struct MountPointEntry {
		std::string mount_point;
		std::string base_dir;
		Headers headers;
	};
	std::vector<MountPointEntry> base_dirs_;

	std::atomic<bool> is_running_;
	std::map<std::string, std::string> file_extension_and_mimetype_map_;
	Handler file_request_handler_;
	Handlers get_handlers_;
	Handlers post_handlers_;
	HandlersForContentReader post_handlers_for_content_reader_;
	Handlers put_handlers_;
	HandlersForContentReader put_handlers_for_content_reader_;
	Handlers patch_handlers_;
	HandlersForContentReader patch_handlers_for_content_reader_;
	Handlers delete_handlers_;
	HandlersForContentReader delete_handlers_for_content_reader_;
	Handlers options_handlers_;
	HandlerWithResponse error_handler_;
	ExceptionHandler exception_handler_;
	HandlerWithResponse pre_routing_handler_;
	Handler post_routing_handler_;
	Logger logger_;
	Expect100ContinueHandler expect_100_continue_handler_;

	int address_family_ = AF_UNSPEC;
	bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
	SocketOptions socket_options_ = default_socket_options;

	Headers default_headers_;
};

enum class Error {
	Success = 0,
	Unknown,
	Connection,
	BindIPAddress,
	Read,
	Write,
	ExceedRedirectCount,
	Canceled,
	SSLConnection,
	SSLLoadingCerts,
	SSLServerVerification,
	UnsupportedMultipartBoundaryChars,
	Compression,
	ConnectionTimeout,
};

std::string to_string(const Error error);

std::ostream &operator<<(std::ostream &os, const Error &obj);

class Result {
public:
	Result(std::unique_ptr<Response> &&res, Error err,
	       Headers &&request_headers = Headers{})
	    : res_(std::move(res)), err_(err),
	      request_headers_(std::move(request_headers)) {}
	// Response
	operator bool() const { return res_ != nullptr; }
	bool operator==(std::nullptr_t) const { return res_ == nullptr; }
	bool operator!=(std::nullptr_t) const { return res_ != nullptr; }
	const Response &value() const { return *res_; }
	Response &value() { return *res_; }
	const Response &operator*() const { return *res_; }
	Response &operator*() { return *res_; }
	const Response *operator->() const { return res_.get(); }
	Response *operator->() { return res_.get(); }

	// Error
	Error error() const { return err_; }

	// Request Headers
	bool has_request_header(const char *key) const;
	std::string get_request_header_value(const char *key, size_t id = 0) const;
	template <typename T>
	T get_request_header_value(const char *key, size_t id = 0) const;
	size_t get_request_header_value_count(const char *key) const;

private:
	std::unique_ptr<Response> res_;
	Error err_;
	Headers request_headers_;
};

class ClientImpl {
public:
	explicit ClientImpl(const std::string &host);

	explicit ClientImpl(const std::string &host, int port);

	explicit ClientImpl(const std::string &host, int port,
	                    const std::string &client_cert_path,
	                    const std::string &client_key_path);

	virtual ~ClientImpl();

	virtual bool is_valid() const;

	Result Get(const char *path);
	Result Get(const char *path, const Headers &headers);
	Result Get(const char *path, Progress progress);
	Result Get(const char *path, const Headers &headers, Progress progress);
	Result Get(const char *path, ContentReceiver content_receiver);
	Result Get(const char *path, const Headers &headers,
	           ContentReceiver content_receiver);
	Result Get(const char *path, ContentReceiver content_receiver,
	           Progress progress);
	Result Get(const char *path, const Headers &headers,
	           ContentReceiver content_receiver, Progress progress);
	Result Get(const char *path, ResponseHandler response_handler,
	           ContentReceiver content_receiver);
	Result Get(const char *path, const Headers &headers,
	           ResponseHandler response_handler,
	           ContentReceiver content_receiver);
	Result Get(const char *path, ResponseHandler response_handler,
	           ContentReceiver content_receiver, Progress progress);
	Result Get(const char *path, const Headers &headers,
	           ResponseHandler response_handler, ContentReceiver content_receiver,
	           Progress progress);

	Result Get(const char *path, const Params &params, const Headers &headers,
	           Progress progress = nullptr);
	Result Get(const char *path, const Params &params, const Headers &headers,
	           ContentReceiver content_receiver, Progress progress = nullptr);
	Result Get(const char *path, const Params &params, const Headers &headers,
	           ResponseHandler response_handler, ContentReceiver content_receiver,
	           Progress progress = nullptr);

	Result Head(const char *path);
	Result Head(const char *path, const Headers &headers);

	Result Post(const char *path);
	Result Post(const char *path, const char *body, size_t content_length,
	            const char *content_type);
	Result Post(const char *path, const Headers &headers, const char *body,
	            size_t content_length, const char *content_type);
	Result Post(const char *path, const std::string &body,
	            const char *content_type);
	Result Post(const char *path, const Headers &headers, const std::string &body,
	            const char *content_type);
	Result Post(const char *path, size_t content_length,
	            ContentProvider content_provider, const char *content_type);
	Result Post(const char *path, ContentProviderWithoutLength content_provider,
	            const char *content_type);
	Result Post(const char *path, const Headers &headers, size_t content_length,
	            ContentProvider content_provider, const char *content_type);
	Result Post(const char *path, const Headers &headers,
	            ContentProviderWithoutLength content_provider,
	            const char *content_type);
	Result Post(const char *path, const Params &params);
	Result Post(const char *path, const Headers &headers, const Params &params);
	Result Post(const char *path, const MultipartFormDataItems &items);
	Result Post(const char *path, const Headers &headers,
	            const MultipartFormDataItems &items);
	Result Post(const char *path, const Headers &headers,
	            const MultipartFormDataItems &items, const std::string &boundary);

	Result Put(const char *path);
	Result Put(const char *path, const char *body, size_t content_length,
	           const char *content_type);
	Result Put(const char *path, const Headers &headers, const char *body,
	           size_t content_length, const char *content_type);
	Result Put(const char *path, const std::string &body,
	           const char *content_type);
	Result Put(const char *path, const Headers &headers, const std::string &body,
	           const char *content_type);
	Result Put(const char *path, size_t content_length,
	           ContentProvider content_provider, const char *content_type);
	Result Put(const char *path, ContentProviderWithoutLength content_provider,
	           const char *content_type);
	Result Put(const char *path, const Headers &headers, size_t content_length,
	           ContentProvider content_provider, const char *content_type);
	Result Put(const char *path, const Headers &headers,
	           ContentProviderWithoutLength content_provider,
	           const char *content_type);
	Result Put(const char *path, const Params &params);
	Result Put(const char *path, const Headers &headers, const Params &params);

	Result Patch(const char *path);
	Result Patch(const char *path, const char *body, size_t content_length,
	             const char *content_type);
	Result Patch(const char *path, const Headers &headers, const char *body,
	             size_t content_length, const char *content_type);
	Result Patch(const char *path, const std::string &body,
	             const char *content_type);
	Result Patch(const char *path, const Headers &headers,
	             const std::string &body, const char *content_type);
	Result Patch(const char *path, size_t content_length,
	             ContentProvider content_provider, const char *content_type);
	Result Patch(const char *path, ContentProviderWithoutLength content_provider,
	             const char *content_type);
	Result Patch(const char *path, const Headers &headers, size_t content_length,
	             ContentProvider content_provider, const char *content_type);
	Result Patch(const char *path, const Headers &headers,
	             ContentProviderWithoutLength content_provider,
	             const char *content_type);

	Result Delete(const char *path);
	Result Delete(const char *path, const Headers &headers);
	Result Delete(const char *path, const char *body, size_t content_length,
	              const char *content_type);
	Result Delete(const char *path, const Headers &headers, const char *body,
	              size_t content_length, const char *content_type);
	Result Delete(const char *path, const std::string &body,
	              const char *content_type);
	Result Delete(const char *path, const Headers &headers,
	              const std::string &body, const char *content_type);

	Result Options(const char *path);
	Result Options(const char *path, const Headers &headers);

	bool send(Request &req, Response &res, Error &error);
	Result send(const Request &req);

	size_t is_socket_open() const;

	void stop();

	void set_hostname_addr_map(const std::map<std::string, std::string> addr_map);

	void set_default_headers(Headers headers);

	void set_address_family(int family);
	void set_tcp_nodelay(bool on);
	void set_socket_options(SocketOptions socket_options);

	void set_connection_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	void
	set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);

	void set_read_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);

	void set_write_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);

	void set_basic_auth(const char *username, const char *password);
	void set_bearer_token_auth(const char *token);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void set_digest_auth(const char *username, const char *password);
#endif

	void set_keep_alive(bool on);
	void set_follow_location(bool on);

	void set_url_encode(bool on);

	void set_compress(bool on);

	void set_decompress(bool on);

	void set_interface(const char *intf);

	void set_proxy(const char *host, int port);
	void set_proxy_basic_auth(const char *username, const char *password);
	void set_proxy_bearer_token_auth(const char *token);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void set_proxy_digest_auth(const char *username, const char *password);
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void set_ca_cert_path(const char *ca_cert_file_path,
	                      const char *ca_cert_dir_path = nullptr);
	void set_ca_cert_store(X509_STORE *ca_cert_store);
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void enable_server_certificate_verification(bool enabled);
#endif

	void set_logger(Logger logger);

protected:
	struct Socket {
		socket_t sock = INVALID_SOCKET;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
		SSL *ssl = nullptr;
#endif

		bool is_open() const { return sock != INVALID_SOCKET; }
	};

	Result send_(Request &&req);

	virtual bool create_and_connect_socket(Socket &socket, Error &error);

	// All of:
	//   shutdown_ssl
	//   shutdown_socket
	//   close_socket
	// should ONLY be called when socket_mutex_ is locked.
	// Also, shutdown_ssl and close_socket should also NOT be called concurrently
	// with a DIFFERENT thread sending requests using that socket.
	virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully);
	void shutdown_socket(Socket &socket);
	void close_socket(Socket &socket);

	bool process_request(Stream &strm, Request &req, Response &res,
	                     bool close_connection, Error &error);

	bool write_content_with_provider(Stream &strm, const Request &req,
	                                 Error &error);

	void copy_settings(const ClientImpl &rhs);

	// Socket endoint information
	const std::string host_;
	const int port_;
	const std::string host_and_port_;

	// Current open socket
	Socket socket_;
	mutable std::mutex socket_mutex_;
	std::recursive_mutex request_mutex_;

	// These are all protected under socket_mutex
	size_t socket_requests_in_flight_ = 0;
	std::thread::id socket_requests_are_from_thread_ = std::thread::id();
	bool socket_should_be_closed_when_request_is_done_ = false;

	// Hostname-IP map
	std::map<std::string, std::string> addr_map_;

	// Default headers
	Headers default_headers_;

	// Settings
	std::string client_cert_path_;
	std::string client_key_path_;

	time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND;
	time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND;
	time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
	time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND;
	time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND;
	time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND;

	std::string basic_auth_username_;
	std::string basic_auth_password_;
	std::string bearer_token_auth_token_;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	std::string digest_auth_username_;
	std::string digest_auth_password_;
#endif

	bool keep_alive_ = false;
	bool follow_location_ = false;

	bool url_encode_ = true;

	int address_family_ = AF_UNSPEC;
	bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
	SocketOptions socket_options_ = nullptr;

	bool compress_ = false;
	bool decompress_ = true;

	std::string interface_;

	std::string proxy_host_;
	int proxy_port_ = -1;

	std::string proxy_basic_auth_username_;
	std::string proxy_basic_auth_password_;
	std::string proxy_bearer_token_auth_token_;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	std::string proxy_digest_auth_username_;
	std::string proxy_digest_auth_password_;
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	std::string ca_cert_file_path_;
	std::string ca_cert_dir_path_;

	X509_STORE *ca_cert_store_ = nullptr;
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	bool server_certificate_verification_ = true;
#endif

	Logger logger_;

private:
	socket_t create_client_socket(Error &error) const;
	bool read_response_line(Stream &strm, const Request &req, Response &res);
	bool write_request(Stream &strm, Request &req, bool close_connection,
	                   Error &error);
	bool redirect(Request &req, Response &res, Error &error);
	bool handle_request(Stream &strm, Request &req, Response &res,
	                    bool close_connection, Error &error);
	std::unique_ptr<Response> send_with_content_provider(
	    Request &req,
	    // const char *method, const char *path, const Headers &headers,
	    const char *body, size_t content_length, ContentProvider content_provider,
	    ContentProviderWithoutLength content_provider_without_length,
	    const char *content_type, Error &error);
	Result send_with_content_provider(
	    const char *method, const char *path, const Headers &headers,
	    const char *body, size_t content_length, ContentProvider content_provider,
	    ContentProviderWithoutLength content_provider_without_length,
	    const char *content_type);

	std::string adjust_host_string(const std::string &host) const;

	virtual bool process_socket(const Socket &socket,
	                            std::function<bool(Stream &strm)> callback);
	virtual bool is_ssl() const;
};

class Client {
public:
	// Universal interface
	explicit Client(const std::string &scheme_host_port);

	explicit Client(const std::string &scheme_host_port,
	                const std::string &client_cert_path,
	                const std::string &client_key_path);

	// HTTP only interface
	explicit Client(const std::string &host, int port);

	explicit Client(const std::string &host, int port,
	                const std::string &client_cert_path,
	                const std::string &client_key_path);

	Client(Client &&) = default;

	~Client();

	bool is_valid() const;

	Result Get(const char *path);
	Result Get(const char *path, const Headers &headers);
	Result Get(const char *path, Progress progress);
	Result Get(const char *path, const Headers &headers, Progress progress);
	Result Get(const char *path, ContentReceiver content_receiver);
	Result Get(const char *path, const Headers &headers,
	           ContentReceiver content_receiver);
	Result Get(const char *path, ContentReceiver content_receiver,
	           Progress progress);
	Result Get(const char *path, const Headers &headers,
	           ContentReceiver content_receiver, Progress progress);
	Result Get(const char *path, ResponseHandler response_handler,
	           ContentReceiver content_receiver);
	Result Get(const char *path, const Headers &headers,
	           ResponseHandler response_handler,
	           ContentReceiver content_receiver);
	Result Get(const char *path, const Headers &headers,
	           ResponseHandler response_handler, ContentReceiver content_receiver,
	           Progress progress);
	Result Get(const char *path, ResponseHandler response_handler,
	           ContentReceiver content_receiver, Progress progress);

	Result Get(const char *path, const Params &params, const Headers &headers,
	           Progress progress = nullptr);
	Result Get(const char *path, const Params &params, const Headers &headers,
	           ContentReceiver content_receiver, Progress progress = nullptr);
	Result Get(const char *path, const Params &params, const Headers &headers,
	           ResponseHandler response_handler, ContentReceiver content_receiver,
	           Progress progress = nullptr);

	Result Head(const char *path);
	Result Head(const char *path, const Headers &headers);

	Result Post(const char *path);
	Result Post(const char *path, const char *body, size_t content_length,
	            const char *content_type);
	Result Post(const char *path, const Headers &headers, const char *body,
	            size_t content_length, const char *content_type);
	Result Post(const char *path, const std::string &body,
	            const char *content_type);
	Result Post(const char *path, const Headers &headers, const std::string &body,
	            const char *content_type);
	Result Post(const char *path, size_t content_length,
	            ContentProvider content_provider, const char *content_type);
	Result Post(const char *path, ContentProviderWithoutLength content_provider,
	            const char *content_type);
	Result Post(const char *path, const Headers &headers, size_t content_length,
	            ContentProvider content_provider, const char *content_type);
	Result Post(const char *path, const Headers &headers,
	            ContentProviderWithoutLength content_provider,
	            const char *content_type);
	Result Post(const char *path, const Params &params);
	Result Post(const char *path, const Headers &headers, const Params &params);
	Result Post(const char *path, const MultipartFormDataItems &items);
	Result Post(const char *path, const Headers &headers,
	            const MultipartFormDataItems &items);
	Result Post(const char *path, const Headers &headers,
	            const MultipartFormDataItems &items, const std::string &boundary);
	Result Put(const char *path);
	Result Put(const char *path, const char *body, size_t content_length,
	           const char *content_type);
	Result Put(const char *path, const Headers &headers, const char *body,
	           size_t content_length, const char *content_type);
	Result Put(const char *path, const std::string &body,
	           const char *content_type);
	Result Put(const char *path, const Headers &headers, const std::string &body,
	           const char *content_type);
	Result Put(const char *path, size_t content_length,
	           ContentProvider content_provider, const char *content_type);
	Result Put(const char *path, ContentProviderWithoutLength content_provider,
	           const char *content_type);
	Result Put(const char *path, const Headers &headers, size_t content_length,
	           ContentProvider content_provider, const char *content_type);
	Result Put(const char *path, const Headers &headers,
	           ContentProviderWithoutLength content_provider,
	           const char *content_type);
	Result Put(const char *path, const Params &params);
	Result Put(const char *path, const Headers &headers, const Params &params);
	Result Patch(const char *path);
	Result Patch(const char *path, const char *body, size_t content_length,
	             const char *content_type);
	Result Patch(const char *path, const Headers &headers, const char *body,
	             size_t content_length, const char *content_type);
	Result Patch(const char *path, const std::string &body,
	             const char *content_type);
	Result Patch(const char *path, const Headers &headers,
	             const std::string &body, const char *content_type);
	Result Patch(const char *path, size_t content_length,
	             ContentProvider content_provider, const char *content_type);
	Result Patch(const char *path, ContentProviderWithoutLength content_provider,
	             const char *content_type);
	Result Patch(const char *path, const Headers &headers, size_t content_length,
	             ContentProvider content_provider, const char *content_type);
	Result Patch(const char *path, const Headers &headers,
	             ContentProviderWithoutLength content_provider,
	             const char *content_type);

	Result Delete(const char *path);
	Result Delete(const char *path, const Headers &headers);
	Result Delete(const char *path, const char *body, size_t content_length,
	              const char *content_type);
	Result Delete(const char *path, const Headers &headers, const char *body,
	              size_t content_length, const char *content_type);
	Result Delete(const char *path, const std::string &body,
	              const char *content_type);
	Result Delete(const char *path, const Headers &headers,
	              const std::string &body, const char *content_type);

	Result Options(const char *path);
	Result Options(const char *path, const Headers &headers);

	bool send(Request &req, Response &res, Error &error);
	Result send(const Request &req);

	size_t is_socket_open() const;

	void stop();

	void set_hostname_addr_map(const std::map<std::string, std::string> addr_map);

	void set_default_headers(Headers headers);

	void set_address_family(int family);
	void set_tcp_nodelay(bool on);
	void set_socket_options(SocketOptions socket_options);

	void set_connection_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	void
	set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);

	void set_read_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);

	void set_write_timeout(time_t sec, time_t usec = 0);
	template <class Rep, class Period>
	void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);

	void set_basic_auth(const char *username, const char *password);
	void set_bearer_token_auth(const char *token);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void set_digest_auth(const char *username, const char *password);
#endif

	void set_keep_alive(bool on);
	void set_follow_location(bool on);

	void set_url_encode(bool on);

	void set_compress(bool on);

	void set_decompress(bool on);

	void set_interface(const char *intf);

	void set_proxy(const char *host, int port);
	void set_proxy_basic_auth(const char *username, const char *password);
	void set_proxy_bearer_token_auth(const char *token);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void set_proxy_digest_auth(const char *username, const char *password);
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void enable_server_certificate_verification(bool enabled);
#endif

	void set_logger(Logger logger);

	// SSL
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	void set_ca_cert_path(const char *ca_cert_file_path,
	                      const char *ca_cert_dir_path = nullptr);

	void set_ca_cert_store(X509_STORE *ca_cert_store);

	long get_openssl_verify_result() const;

	SSL_CTX *ssl_context() const;
#endif

private:
	std::unique_ptr<ClientImpl> cli_;

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	bool is_ssl_ = false;
#endif
};

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
class SSLServer : public Server {
public:
	SSLServer(const char *cert_path, const char *private_key_path,
	          const char *client_ca_cert_file_path = nullptr,
	          const char *client_ca_cert_dir_path = nullptr);

	SSLServer(X509 *cert, EVP_PKEY *private_key,
	          X509_STORE *client_ca_cert_store = nullptr);

	SSLServer(
	    const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback);

	~SSLServer() override;

	bool is_valid() const override;

	SSL_CTX *ssl_context() const;

private:
	bool process_and_close_socket(socket_t sock) override;

	SSL_CTX *ctx_;
	std::mutex ctx_mutex_;
};

class SSLClient : public ClientImpl {
public:
	explicit SSLClient(const std::string &host);

	explicit SSLClient(const std::string &host, int port);

	explicit SSLClient(const std::string &host, int port,
	                   const std::string &client_cert_path,
	                   const std::string &client_key_path);

	explicit SSLClient(const std::string &host, int port, X509 *client_cert,
	                   EVP_PKEY *client_key);

	~SSLClient() override;

	bool is_valid() const override;

	void set_ca_cert_store(X509_STORE *ca_cert_store);

	long get_openssl_verify_result() const;

	SSL_CTX *ssl_context() const;

private:
	bool create_and_connect_socket(Socket &socket, Error &error) override;
	void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
	void shutdown_ssl_impl(Socket &socket, bool shutdown_socket);

	bool process_socket(const Socket &socket,
	                    std::function<bool(Stream &strm)> callback) override;
	bool is_ssl() const override;

	bool connect_with_proxy(Socket &sock, Response &res, bool &success,
	                        Error &error);
	bool initialize_ssl(Socket &socket, Error &error);

	bool load_certs();

	bool verify_host(X509 *server_cert) const;
	bool verify_host_with_subject_alt_name(X509 *server_cert) const;
	bool verify_host_with_common_name(X509 *server_cert) const;
	bool check_host_name(const char *pattern, size_t pattern_len) const;

	SSL_CTX *ctx_;
	std::mutex ctx_mutex_;
	std::once_flag initialize_cert_;

	std::vector<std::string> host_components_;

	long verify_result_ = 0;

	friend class ClientImpl;
};
#endif

/*
 * Implementation of template methods.
 */

namespace detail {

template <typename T, typename U>
inline void duration_to_sec_and_usec(const T &duration, U callback) {
	auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
	auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
	                duration - std::chrono::seconds(sec))
	                .count();
	callback(sec, usec);
}

template <typename T>
inline T get_header_value(const Headers & /*headers*/, const char * /*key*/,
                          size_t /*id*/ = 0, uint64_t /*def*/ = 0) {}

template <>
inline uint64_t get_header_value<uint64_t>(const Headers &headers,
                                           const char *key, size_t id,
                                           uint64_t def) {
	auto rng = headers.equal_range(key);
	auto it = rng.first;
	std::advance(it, static_cast<ssize_t>(id));
	if (it != rng.second) {
		return std::strtoull(it->second.data(), nullptr, 10);
	}
	return def;
}

} // namespace detail

template <typename T>
inline T Request::get_header_value(const char *key, size_t id) const {
	return detail::get_header_value<T>(headers, key, id, 0);
}

template <typename T>
inline T Response::get_header_value(const char *key, size_t id) const {
	return detail::get_header_value<T>(headers, key, id, 0);
}

template <typename... Args>
inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
	const auto bufsiz = 2048;
	std::array<char, bufsiz> buf{};

#if defined(_MSC_VER) && _MSC_VER < 1900
	auto sn = _snprintf_s(buf.data(), bufsiz, _TRUNCATE, fmt, args...);
#else
	auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
#endif
	if (sn <= 0) { return sn; }

	auto n = static_cast<size_t>(sn);

	if (n >= buf.size() - 1) {
		std::vector<char> glowable_buf(buf.size());

		while (n >= glowable_buf.size() - 1) {
			glowable_buf.resize(glowable_buf.size() * 2);
#if defined(_MSC_VER) && _MSC_VER < 1900
			n = static_cast<size_t>(_snprintf_s(&glowable_buf[0], glowable_buf.size(),
			                                    glowable_buf.size() - 1, fmt,
			                                    args...));
#else
			n = static_cast<size_t>(
			    snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...));
#endif
		}
		return write(&glowable_buf[0], n);
	} else {
		return write(buf.data(), n);
	}
}

inline void default_socket_options(socket_t sock) {
	int yes = 1;
#ifdef _WIN32
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes),
	           sizeof(yes));
	setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
	           reinterpret_cast<char *>(&yes), sizeof(yes));
#else
#ifdef SO_REUSEPORT
	setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<void *>(&yes),
	           sizeof(yes));
#else
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<void *>(&yes),
	           sizeof(yes));
#endif
#endif
}

template <class Rep, class Period>
inline Server &
Server::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
	detail::duration_to_sec_and_usec(
	    duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
	return *this;
}

template <class Rep, class Period>
inline Server &
Server::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
	detail::duration_to_sec_and_usec(
	    duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
	return *this;
}

template <class Rep, class Period>
inline Server &
Server::set_idle_interval(const std::chrono::duration<Rep, Period> &duration) {
	detail::duration_to_sec_and_usec(
	    duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); });
	return *this;
}

inline std::string to_string(const Error error) {
	switch (error) {
	case Error::Success: return "Success";
	case Error::Connection: return "Connection";
	case Error::BindIPAddress: return "BindIPAddress";
	case Error::Read: return "Read";
	case Error::Write: return "Write";
	case Error::ExceedRedirectCount: return "ExceedRedirectCount";
	case Error::Canceled: return "Canceled";
	case Error::SSLConnection: return "SSLConnection";
	case Error::SSLLoadingCerts: return "SSLLoadingCerts";
	case Error::SSLServerVerification: return "SSLServerVerification";
	case Error::UnsupportedMultipartBoundaryChars:
		return "UnsupportedMultipartBoundaryChars";
	case Error::Compression: return "Compression";
	case Error::ConnectionTimeout: return "ConnectionTimeout";
	case Error::Unknown: return "Unknown";
	default: break;
	}

	return "Invalid";
}

inline std::ostream &operator<<(std::ostream &os, const Error &obj) {
	os << to_string(obj);
	os << " (" << static_cast<std::underlying_type<Error>::type>(obj) << ')';
	return os;
}

template <typename T>
inline T Result::get_request_header_value(const char *key, size_t id) const {
	return detail::get_header_value<T>(request_headers_, key, id, 0);
}

template <class Rep, class Period>
inline void ClientImpl::set_connection_timeout(
    const std::chrono::duration<Rep, Period> &duration) {
	detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
		set_connection_timeout(sec, usec);
	});
}

template <class Rep, class Period>
inline void ClientImpl::set_read_timeout(
    const std::chrono::duration<Rep, Period> &duration) {
	detail::duration_to_sec_and_usec(
	    duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
}

template <class Rep, class Period>
inline void ClientImpl::set_write_timeout(
    const std::chrono::duration<Rep, Period> &duration) {
	detail::duration_to_sec_and_usec(
	    duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
}

template <class Rep, class Period>
inline void Client::set_connection_timeout(
    const std::chrono::duration<Rep, Period> &duration) {
	cli_->set_connection_timeout(duration);
}

template <class Rep, class Period>
inline void
Client::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
	cli_->set_read_timeout(duration);
}

template <class Rep, class Period>
inline void
Client::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
	cli_->set_write_timeout(duration);
}

/*
 * Forward declarations and types that will be part of the .h file if split into
 * .h + .cc.
 */

std::string hosted_at(const char *hostname);

void hosted_at(const char *hostname, std::vector<std::string> &addrs);

std::string append_query_params(const char *path, const Params &params);

std::pair<std::string, std::string> make_range_header(Ranges ranges);

std::pair<std::string, std::string>
make_basic_authentication_header(const std::string &username,
                                 const std::string &password,
                                 bool is_proxy = false);

namespace detail {

std::string encode_query_param(const std::string &value);

std::string decode_url(const std::string &s, bool convert_plus_to_space);

void read_file(const std::string &path, std::string &out);

std::string trim_copy(const std::string &s);

void split(const char *b, const char *e, char d,
           std::function<void(const char *, const char *)> fn);

bool process_client_socket(socket_t sock, time_t read_timeout_sec,
                           time_t read_timeout_usec, time_t write_timeout_sec,
                           time_t write_timeout_usec,
                           std::function<bool(Stream &)> callback);

socket_t create_client_socket(
    const char *host, const char *ip, int port, int address_family,
    bool tcp_nodelay, SocketOptions socket_options,
    time_t connection_timeout_sec, time_t connection_timeout_usec,
    time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
    time_t write_timeout_usec, const std::string &intf, Error &error);

const char *get_header_value(const Headers &headers, const char *key,
                             size_t id = 0, const char *def = nullptr);

std::string params_to_query_str(const Params &params);

void parse_query_text(const std::string &s, Params &params);

bool parse_range_header(const std::string &s, Ranges &ranges);

int close_socket(socket_t sock);

ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags);

ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags);

enum class EncodingType { None = 0, Gzip, Brotli };

EncodingType encoding_type(const Request &req, const Response &res);

class BufferStream : public Stream {
public:
	BufferStream() = default;
	~BufferStream() override = default;

	bool is_readable() const override;
	bool is_writable() const override;
	ssize_t read(char *ptr, size_t size) override;
	ssize_t write(const char *ptr, size_t size) override;
	void get_remote_ip_and_port(std::string &ip, int &port) const override;
	socket_t socket() const override;

	const std::string &get_buffer() const;

private:
	std::string buffer;
	size_t position = 0;
};

class compressor {
public:
	virtual ~compressor() = default;

	typedef std::function<bool(const char *data, size_t data_len)> Callback;
	virtual bool compress(const char *data, size_t data_length, bool last,
	                      Callback callback) = 0;
};

class decompressor {
public:
	virtual ~decompressor() = default;

	virtual bool is_valid() const = 0;

	typedef std::function<bool(const char *data, size_t data_len)> Callback;
	virtual bool decompress(const char *data, size_t data_length,
	                        Callback callback) = 0;
};

class nocompressor : public compressor {
public:
	virtual ~nocompressor() = default;

	bool compress(const char *data, size_t data_length, bool /*last*/,
	              Callback callback) override;
};

#ifdef CPPHTTPLIB_ZLIB_SUPPORT
class gzip_compressor : public compressor {
public:
	gzip_compressor();
	~gzip_compressor();

	bool compress(const char *data, size_t data_length, bool last,
	              Callback callback) override;

private:
	bool is_valid_ = false;
	z_stream strm_;
};

class gzip_decompressor : public decompressor {
public:
	gzip_decompressor();
	~gzip_decompressor();

	bool is_valid() const override;

	bool decompress(const char *data, size_t data_length,
	                Callback callback) override;

private:
	bool is_valid_ = false;
	z_stream strm_;
};
#endif

#ifdef CPPHTTPLIB_BROTLI_SUPPORT
class brotli_compressor : public compressor {
public:
	brotli_compressor();
	~brotli_compressor();

	bool compress(const char *data, size_t data_length, bool last,
	              Callback callback) override;

private:
	BrotliEncoderState *state_ = nullptr;
};

class brotli_decompressor : public decompressor {
public:
	brotli_decompressor();
	~brotli_decompressor();

	bool is_valid() const override;

	bool decompress(const char *data, size_t data_length,
	                Callback callback) override;

private:
	BrotliDecoderResult decoder_r;
	BrotliDecoderState *decoder_s = nullptr;
};
#endif

// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer`
// to store data. The call can set memory on stack for performance.
class stream_line_reader {
public:
	stream_line_reader(Stream &strm, char *fixed_buffer,
	                   size_t fixed_buffer_size);
	const char *ptr() const;
	size_t size() const;
	bool end_with_crlf() const;
	bool getline();

private:
	void append(char c);

	Stream &strm_;
	char *fixed_buffer_;
	const size_t fixed_buffer_size_;
	size_t fixed_buffer_used_size_ = 0;
	std::string glowable_buffer_;
};

} // namespace detail

// ----------------------------------------------------------------------------

/*
 * Implementation that will be part of the .cc file if split into .h + .cc.
 */

namespace detail {

inline bool is_hex(char c, int &v) {
	if (0x20 <= c && isdigit(c)) {
		v = c - '0';
		return true;
	} else if ('A' <= c && c <= 'F') {
		v = c - 'A' + 10;
		return true;
	} else if ('a' <= c && c <= 'f') {
		v = c - 'a' + 10;
		return true;
	}
	return false;
}

inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,
                          int &val) {
	if (i >= s.size()) { return false; }

	val = 0;
	for (; cnt; i++, cnt--) {
		if (!s[i]) { return false; }
		int v = 0;
		if (is_hex(s[i], v)) {
			val = val * 16 + v;
		} else {
			return false;
		}
	}
	return true;
}

inline std::string from_i_to_hex(size_t n) {
	const char *charset = "0123456789abcdef";
	std::string ret;
	do {
		ret = charset[n & 15] + ret;
		n >>= 4;
	} while (n > 0);
	return ret;
}

inline size_t to_utf8(int code, char *buff) {
	if (code < 0x0080) {
		buff[0] = (code & 0x7F);
		return 1;
	} else if (code < 0x0800) {
		buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
		buff[1] = static_cast<char>(0x80 | (code & 0x3F));
		return 2;
	} else if (code < 0xD800) {
		buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
		buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
		buff[2] = static_cast<char>(0x80 | (code & 0x3F));
		return 3;
	} else if (code < 0xE000) { // D800 - DFFF is invalid...
		return 0;
	} else if (code < 0x10000) {
		buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
		buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
		buff[2] = static_cast<char>(0x80 | (code & 0x3F));
		return 3;
	} else if (code < 0x110000) {
		buff[0] = static_cast<char>(0xF0 | ((code >> 18) & 0x7));
		buff[1] = static_cast<char>(0x80 | ((code >> 12) & 0x3F));
		buff[2] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
		buff[3] = static_cast<char>(0x80 | (code & 0x3F));
		return 4;
	}

	// NOTREACHED
	return 0;
}

// NOTE: This code came up with the following stackoverflow post:
// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
inline std::string base64_encode(const std::string &in) {
	static const auto lookup =
	    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

	std::string out;
	out.reserve(in.size());

	int val = 0;
	int valb = -6;

	for (auto c : in) {
		val = (val << 8) + static_cast<uint8_t>(c);
		valb += 8;
		while (valb >= 0) {
			out.push_back(lookup[(val >> valb) & 0x3F]);
			valb -= 6;
		}
	}

	if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); }

	while (out.size() % 4) {
		out.push_back('=');
	}

	return out;
}

inline bool is_file(const std::string &path) {
#ifdef _WIN32
	return _access_s(path.c_str(), 0) == 0;
#else
	struct stat st;
	return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
#endif
}

inline bool is_dir(const std::string &path) {
	struct stat st;
	return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
}

inline bool is_valid_path(const std::string &path) {
	size_t level = 0;
	size_t i = 0;

	// Skip slash
	while (i < path.size() && path[i] == '/') {
		i++;
	}

	while (i < path.size()) {
		// Read component
		auto beg = i;
		while (i < path.size() && path[i] != '/') {
			i++;
		}

		auto len = i - beg;
		assert(len > 0);

		if (!path.compare(beg, len, ".")) {
			;
		} else if (!path.compare(beg, len, "..")) {
			if (level == 0) { return false; }
			level--;
		} else {
			level++;
		}

		// Skip slash
		while (i < path.size() && path[i] == '/') {
			i++;
		}
	}

	return true;
}

inline std::string encode_query_param(const std::string &value) {
	std::ostringstream escaped;
	escaped.fill('0');
	escaped << std::hex;

	for (auto c : value) {
		if (std::isalnum(static_cast<uint8_t>(c)) || c == '-' || c == '_' ||
		    c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' ||
		    c == ')') {
			escaped << c;
		} else {
			escaped << std::uppercase;
			escaped << '%' << std::setw(2)
			        << static_cast<int>(static_cast<unsigned char>(c));
			escaped << std::nouppercase;
		}
	}

	return escaped.str();
}

inline std::string encode_url(const std::string &s) {
	std::string result;
	result.reserve(s.size());

	for (size_t i = 0; s[i]; i++) {
		switch (s[i]) {
		case ' ': result += "%20"; break;
//		case '+': result += "%2B"; break;
		case '\r': result += "%0D"; break;
		case '\n': result += "%0A"; break;
		case '\'': result += "%27"; break;
		case ',': result += "%2C"; break;
		// case ':': result += "%3A"; break; // ok? probably...
		case ';': result += "%3B"; break;
		default:
			auto c = static_cast<uint8_t>(s[i]);
			if (c >= 0x80) {
				result += '%';
				char hex[4];
				auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
				assert(len == 2);
				result.append(hex, static_cast<size_t>(len));
			} else {
				result += s[i];
			}
			break;
		}
	}

	return result;
}

inline std::string decode_url(const std::string &s,
                              bool convert_plus_to_space) {
	std::string result;

	for (size_t i = 0; i < s.size(); i++) {
		if (s[i] == '%' && i + 1 < s.size()) {
			if (s[i + 1] == 'u') {
				int val = 0;
				if (from_hex_to_i(s, i + 2, 4, val)) {
					// 4 digits Unicode codes
					char buff[4];
					size_t len = to_utf8(val, buff);
					if (len > 0) { result.append(buff, len); }
					i += 5; // 'u0000'
				} else {
					result += s[i];
				}
			} else {
				int val = 0;
				if (from_hex_to_i(s, i + 1, 2, val)) {
					// 2 digits hex codes
					if (static_cast<char>(val) == '+'){
						// We don't decode +
						result += "%2B";
					} else {
						result += static_cast<char>(val);
					}
					i += 2; // '00'
				} else {
					result += s[i];
				}
			}
		} else if (convert_plus_to_space && s[i] == '+') {
			result += ' ';
		} else {
			result += s[i];
		}
	}

	return result;
}

inline void read_file(const std::string &path, std::string &out) {
	std::ifstream fs(path, std::ios_base::binary);
	fs.seekg(0, std::ios_base::end);
	auto size = fs.tellg();
	fs.seekg(0);
	out.resize(static_cast<size_t>(size));
	fs.read(&out[0], static_cast<std::streamsize>(size));
}

inline std::string file_extension(const std::string &path) {
	Match m;
	static Regex re("\\.([a-zA-Z0-9]+)$");
	if (duckdb_re2::RegexSearch(path, m, re)) { return m.str(1); }
	return std::string();
}

inline bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; }

inline std::pair<size_t, size_t> trim(const char *b, const char *e, size_t left,
                                      size_t right) {
	while (b + left < e && is_space_or_tab(b[left])) {
		left++;
	}
	while (right > 0 && is_space_or_tab(b[right - 1])) {
		right--;
	}
	return std::make_pair(left, right);
}

inline std::string trim_copy(const std::string &s) {
	auto r = trim(s.data(), s.data() + s.size(), 0, s.size());
	return s.substr(r.first, r.second - r.first);
}

inline void split(const char *b, const char *e, char d,
                  std::function<void(const char *, const char *)> fn) {
	size_t i = 0;
	size_t beg = 0;

	while (e ? (b + i < e) : (b[i] != '\0')) {
		if (b[i] == d) {
			auto r = trim(b, e, beg, i);
			if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
			beg = i + 1;
		}
		i++;
	}

	if (i) {
		auto r = trim(b, e, beg, i);
		if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
	}
}

inline stream_line_reader::stream_line_reader(Stream &strm, char *fixed_buffer,
                                              size_t fixed_buffer_size)
    : strm_(strm), fixed_buffer_(fixed_buffer),
      fixed_buffer_size_(fixed_buffer_size) {}

inline const char *stream_line_reader::ptr() const {
	if (glowable_buffer_.empty()) {
		return fixed_buffer_;
	} else {
		return glowable_buffer_.data();
	}
}

inline size_t stream_line_reader::size() const {
	if (glowable_buffer_.empty()) {
		return fixed_buffer_used_size_;
	} else {
		return glowable_buffer_.size();
	}
}

inline bool stream_line_reader::end_with_crlf() const {
	auto end = ptr() + size();
	return size() >= 2 && end[-2] == '\r' && end[-1] == '\n';
}

inline bool stream_line_reader::getline() {
	fixed_buffer_used_size_ = 0;
	glowable_buffer_.clear();

	for (size_t i = 0;; i++) {
		char byte;
		auto n = strm_.read(&byte, 1);

		if (n < 0) {
			return false;
		} else if (n == 0) {
			if (i == 0) {
				return false;
			} else {
				break;
			}
		}

		append(byte);

		if (byte == '\n') { break; }
	}

	return true;
}

inline void stream_line_reader::append(char c) {
	if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) {
		fixed_buffer_[fixed_buffer_used_size_++] = c;
		fixed_buffer_[fixed_buffer_used_size_] = '\0';
	} else {
		if (glowable_buffer_.empty()) {
			assert(fixed_buffer_[fixed_buffer_used_size_] == '\0');
			glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_);
		}
		glowable_buffer_ += c;
	}
}

inline int close_socket(socket_t sock) {
#ifdef _WIN32
	return closesocket(sock);
#else
	return close(sock);
#endif
}

template <typename T> inline ssize_t handle_EINTR(T fn) {
	ssize_t res = false;
	while (true) {
		res = fn();
		if (res < 0 && errno == EINTR) { continue; }
		break;
	}
	return res;
}

inline ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) {
	return handle_EINTR([&]() {
		return recv(sock,
#ifdef _WIN32
		            static_cast<char *>(ptr), static_cast<int>(size),
#else
		            ptr, size,
#endif
		            flags);
	});
}

inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size,
                           int flags) {
	return handle_EINTR([&]() {
		return send(sock,
#ifdef _WIN32
		            static_cast<const char *>(ptr), static_cast<int>(size),
#else
		            ptr, size,
#endif
		            flags);
	});
}

inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
#ifdef CPPHTTPLIB_USE_POLL
	struct pollfd pfd_read;
	pfd_read.fd = sock;
	pfd_read.events = POLLIN;

	auto timeout = static_cast<int>(sec * 1000 + usec / 1000);

	return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
#else
#ifndef _WIN32
	if (sock >= FD_SETSIZE) { return 1; }
#endif

	fd_set fds;
	FD_ZERO(&fds);
	FD_SET(sock, &fds);

	timeval tv;
	tv.tv_sec = static_cast<long>(sec);
	tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);

	return handle_EINTR([&]() {
		return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
	});
#endif
}

inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
#ifdef CPPHTTPLIB_USE_POLL
	struct pollfd pfd_read;
	pfd_read.fd = sock;
	pfd_read.events = POLLOUT;

	auto timeout = static_cast<int>(sec * 1000 + usec / 1000);

	return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
#else
#ifndef _WIN32
	if (sock >= FD_SETSIZE) { return 1; }
#endif

	fd_set fds;
	FD_ZERO(&fds);
	FD_SET(sock, &fds);

	timeval tv;
	tv.tv_sec = static_cast<long>(sec);
	tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);

	return handle_EINTR([&]() {
		return select(static_cast<int>(sock + 1), nullptr, &fds, nullptr, &tv);
	});
#endif
}

inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
#ifdef CPPHTTPLIB_USE_POLL
	struct pollfd pfd_read;
	pfd_read.fd = sock;
	pfd_read.events = POLLIN | POLLOUT;

	auto timeout = static_cast<int>(sec * 1000 + usec / 1000);

	auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });

	if (poll_res == 0) {
		return Error::ConnectionTimeout;
	}

	if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
		int error = 0;
		socklen_t len = sizeof(error);
		auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
		                      reinterpret_cast<char *>(&error), &len);
		auto successful = res >= 0 && !error;
		return successful ? Error::Success : Error::Connection;
	}

	return Error::Connection;
#else
#ifndef _WIN32
	if (sock >= FD_SETSIZE) { return Error::Connection; }
#endif

	fd_set fdsr;
	FD_ZERO(&fdsr);
	FD_SET(sock, &fdsr);

	auto fdsw = fdsr;
	auto fdse = fdsr;

	timeval tv;
	tv.tv_sec = static_cast<long>(sec);
	tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);

	auto ret = handle_EINTR([&]() {
		return select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv);
	});

	if (ret == 0) {
		return Error::ConnectionTimeout;
	}

	if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
		int error = 0;
		socklen_t len = sizeof(error);
		auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
		                      reinterpret_cast<char *>(&error), &len);
		auto successful = res >= 0 && !error;
		return successful ? Error::Success : Error::Connection;
	}
	return Error::Connection;
#endif
}

inline bool is_socket_alive(socket_t sock) {
	const auto val = detail::select_read(sock, 0, 0);
	if (val == 0) {
		return true;
	} else if (val < 0 && errno == EBADF) {
		return false;
	}
	char buf[1];
	return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0;
}

class SocketStream : public Stream {
public:
	SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
	             time_t write_timeout_sec, time_t write_timeout_usec);
	~SocketStream() override;

	bool is_readable() const override;
	bool is_writable() const override;
	ssize_t read(char *ptr, size_t size) override;
	ssize_t write(const char *ptr, size_t size) override;
	void get_remote_ip_and_port(std::string &ip, int &port) const override;
	socket_t socket() const override;

private:
	socket_t sock_;
	time_t read_timeout_sec_;
	time_t read_timeout_usec_;
	time_t write_timeout_sec_;
	time_t write_timeout_usec_;

	std::vector<char> read_buff_;
	size_t read_buff_off_ = 0;
	size_t read_buff_content_size_ = 0;

	static const size_t read_buff_size_ = 1024 * 4;
};

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
class SSLSocketStream : public Stream {
public:
	SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec,
	                time_t read_timeout_usec, time_t write_timeout_sec,
	                time_t write_timeout_usec);
	~SSLSocketStream() override;

	bool is_readable() const override;
	bool is_writable() const override;
	ssize_t read(char *ptr, size_t size) override;
	ssize_t write(const char *ptr, size_t size) override;
	void get_remote_ip_and_port(std::string &ip, int &port) const override;
	socket_t socket() const override;

private:
	socket_t sock_;
	SSL *ssl_;
	time_t read_timeout_sec_;
	time_t read_timeout_usec_;
	time_t write_timeout_sec_;
	time_t write_timeout_usec_;
};
#endif

inline bool keep_alive(socket_t sock, time_t keep_alive_timeout_sec) {
	using namespace std::chrono;
	auto start = steady_clock::now();
	while (true) {
		auto val = select_read(sock, 0, 10000);
		if (val < 0) {
			return false;
		} else if (val == 0) {
			auto current = steady_clock::now();
			auto duration = duration_cast<milliseconds>(current - start);
			auto timeout = keep_alive_timeout_sec * 1000;
			if (duration.count() > timeout) { return false; }
			std::this_thread::sleep_for(std::chrono::milliseconds(1));
		} else {
			return true;
		}
	}
}

template <typename T>
inline bool
process_server_socket_core(const std::atomic<socket_t> &svr_sock, socket_t sock,
                           size_t keep_alive_max_count,
                           time_t keep_alive_timeout_sec, T callback) {
	assert(keep_alive_max_count > 0);
	auto ret = false;
	auto count = keep_alive_max_count;
	while (svr_sock != INVALID_SOCKET && count > 0 &&
	       keep_alive(sock, keep_alive_timeout_sec)) {
		auto close_connection = count == 1;
		auto connection_closed = false;
		ret = callback(close_connection, connection_closed);
		if (!ret || connection_closed) { break; }
		count--;
	}
	return ret;
}

template <typename T>
inline bool
process_server_socket(const std::atomic<socket_t> &svr_sock, socket_t sock,
                      size_t keep_alive_max_count,
                      time_t keep_alive_timeout_sec, time_t read_timeout_sec,
                      time_t read_timeout_usec, time_t write_timeout_sec,
                      time_t write_timeout_usec, T callback) {
	return process_server_socket_core(
	    svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
	    [&](bool close_connection, bool &connection_closed) {
		    SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
		                      write_timeout_sec, write_timeout_usec);
		    return callback(strm, close_connection, connection_closed);
	    });
}

inline bool process_client_socket(socket_t sock, time_t read_timeout_sec,
                                  time_t read_timeout_usec,
                                  time_t write_timeout_sec,
                                  time_t write_timeout_usec,
                                  std::function<bool(Stream &)> callback) {
	SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
	                  write_timeout_sec, write_timeout_usec);
	return callback(strm);
}

inline int shutdown_socket(socket_t sock) {
#ifdef _WIN32
	return shutdown(sock, SD_BOTH);
#else
	return shutdown(sock, SHUT_RDWR);
#endif
}

template <typename BindOrConnect>
socket_t create_socket(const char *host, const char *ip, int port,
                       int address_family, int socket_flags, bool tcp_nodelay,
                       SocketOptions socket_options,
                       BindOrConnect bind_or_connect) {
	// Get address info
	const char *node = nullptr;
	struct addrinfo hints;
	struct addrinfo *result;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;

	if (ip[0] != '\0') {
		node = ip;
		// Ask getaddrinfo to convert IP in c-string to address
		hints.ai_family = AF_UNSPEC;
		hints.ai_flags = AI_NUMERICHOST;
	} else {
		node = host;
		hints.ai_family = address_family;
		hints.ai_flags = socket_flags;
	}

	auto service = std::to_string(port);

	if (getaddrinfo(node, service.c_str(), &hints, &result)) {
#if defined __linux__ && !defined __ANDROID__
		res_init();
#endif
		return INVALID_SOCKET;
	}

	for (auto rp = result; rp; rp = rp->ai_next) {
		// Create a socket
#ifdef _WIN32
		auto sock =
		    WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0,
		               WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
		/**
     * Since the WSA_FLAG_NO_HANDLE_INHERIT is only supported on Windows 7 SP1
     * and above the socket creation fails on older Windows Systems.
     *
     * Let's try to create a socket the old way in this case.
     *
     * Reference:
     * https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketa
     *
     * WSA_FLAG_NO_HANDLE_INHERIT:
     * This flag is supported on Windows 7 with SP1, Windows Server 2008 R2 with
     * SP1, and later
     *
		 */
		if (sock == INVALID_SOCKET) {
			sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
		}
#else
		auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
#endif
		if (sock == INVALID_SOCKET) { continue; }

#ifndef _WIN32
		if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { continue; }
#endif

		if (tcp_nodelay) {
			int yes = 1;
			setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&yes),
			           sizeof(yes));
		}

		if (socket_options) { socket_options(sock); }

		if (rp->ai_family == AF_INET6) {
			int no = 0;
			setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&no),
			           sizeof(no));
		}

		// bind or connect
		if (bind_or_connect(sock, *rp)) {
			freeaddrinfo(result);
			return sock;
		}

		close_socket(sock);
	}

	freeaddrinfo(result);
	return INVALID_SOCKET;
}

inline void set_nonblocking(socket_t sock, bool nonblocking) {
#ifdef _WIN32
	auto flags = nonblocking ? 1UL : 0UL;
	ioctlsocket(sock, FIONBIO, &flags);
#else
	auto flags = fcntl(sock, F_GETFL, 0);
	fcntl(sock, F_SETFL,
	      nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK)));
#endif
}

inline bool is_connection_error() {
#ifdef _WIN32
	return WSAGetLastError() != WSAEWOULDBLOCK;
#else
	return errno != EINPROGRESS;
#endif
}

inline bool bind_ip_address(socket_t sock, const char *host) {
	struct addrinfo hints;
	struct addrinfo *result;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;

	if (getaddrinfo(host, "0", &hints, &result)) { return false; }

	auto ret = false;
	for (auto rp = result; rp; rp = rp->ai_next) {
		const auto &ai = *rp;
		if (!::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
			ret = true;
			break;
		}
	}

	freeaddrinfo(result);
	return ret;
}

#if !defined _WIN32 && !defined ANDROID
#define USE_IF2IP
#endif

#ifdef USE_IF2IP
inline std::string if2ip(const std::string &ifn) {
	struct ifaddrs *ifap;
	getifaddrs(&ifap);
	for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
		if (ifa->ifa_addr && ifn == ifa->ifa_name) {
			if (ifa->ifa_addr->sa_family == AF_INET) {
				auto sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
				char buf[INET_ADDRSTRLEN];
				if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) {
					freeifaddrs(ifap);
					return std::string(buf, INET_ADDRSTRLEN);
				}
			}
		}
	}
	freeifaddrs(ifap);
	return std::string();
}
#endif

inline socket_t create_client_socket(
    const char *host, const char *ip, int port, int address_family,
    bool tcp_nodelay, SocketOptions socket_options,
    time_t connection_timeout_sec, time_t connection_timeout_usec,
    time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
    time_t write_timeout_usec, const std::string &intf, Error &error) {
	auto sock = create_socket(
	    host, ip, port, address_family, 0, tcp_nodelay, std::move(socket_options),
	    [&](socket_t sock2, struct addrinfo &ai) -> bool {
		    if (!intf.empty()) {
#ifdef USE_IF2IP
			    auto ip = if2ip(intf);
			    if (ip.empty()) { ip = intf; }
			    if (!bind_ip_address(sock2, ip.c_str())) {
				    error = Error::BindIPAddress;
				    return false;
			    }
#endif
		    }

		    set_nonblocking(sock2, true);

		    auto ret =
		        ::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen));

		    if (ret < 0) {
			    if (is_connection_error()) {
				    error = Error::Connection;
				    return false;
			    }
			    error = wait_until_socket_is_ready(sock2, connection_timeout_sec,
			                                       connection_timeout_usec);
			    if (error != Error::Success) {
				    return false;
			    }
		    }

		    set_nonblocking(sock2, false);

		    {
#ifdef _WIN32
			    auto timeout = static_cast<uint32_t>(read_timeout_sec * 1000 +
			                                         read_timeout_usec / 1000);
			    setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
			               sizeof(timeout));
#else
			    timeval tv;
			    tv.tv_sec = static_cast<long>(read_timeout_sec);
			    tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
			    setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
#endif
		    }
		    {

#ifdef _WIN32
			    auto timeout = static_cast<uint32_t>(write_timeout_sec * 1000 +
			                                         write_timeout_usec / 1000);
			    setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
			               sizeof(timeout));
#else
			    timeval tv;
			    tv.tv_sec = static_cast<long>(write_timeout_sec);
			    tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
			    setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
#endif
		    }

		    error = Error::Success;
		    return true;
	    });

	if (sock != INVALID_SOCKET) {
		error = Error::Success;
	} else {
		if (error == Error::Success) { error = Error::Connection; }
	}

	return sock;
}

inline bool get_remote_ip_and_port(const struct sockaddr_storage &addr,
                                   socklen_t addr_len, std::string &ip,
                                   int &port) {
	if (addr.ss_family == AF_INET) {
		port = ntohs(reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_port);
	} else if (addr.ss_family == AF_INET6) {
		port =
		    ntohs(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_port);
	} else {
		return false;
	}

	std::array<char, NI_MAXHOST> ipstr{};
	if (getnameinfo(reinterpret_cast<const struct sockaddr *>(&addr), addr_len,
	                ipstr.data(), static_cast<socklen_t>(ipstr.size()), nullptr,
	                0, NI_NUMERICHOST)) {
		return false;
	}

	ip = ipstr.data();
	return true;
}

inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
	struct sockaddr_storage addr;
	socklen_t addr_len = sizeof(addr);

	if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr),
	                 &addr_len)) {
		get_remote_ip_and_port(addr, addr_len, ip, port);
	}
}

inline constexpr unsigned int str2tag_core(const char *s, size_t l,
                                           unsigned int h) {
	return (l == 0) ? h
	                : str2tag_core(s + 1, l - 1,
	                               (h * 33) ^ static_cast<unsigned char>(*s));
}

inline unsigned int str2tag(const std::string &s) {
	return str2tag_core(s.data(), s.size(), 0);
}

namespace udl {

inline constexpr unsigned int operator"" _t(const char *s, size_t l) {
	return str2tag_core(s, l, 0);
}

} // namespace udl

inline const char *
find_content_type(const std::string &path,
                  const std::map<std::string, std::string> &user_data) {
	auto ext = file_extension(path);

	auto it = user_data.find(ext);
	if (it != user_data.end()) { return it->second.c_str(); }

	using udl::operator"" _t;

	switch (str2tag(ext)) {
	default: return nullptr;
	case "css"_t: return "text/css";
	case "csv"_t: return "text/csv";
	case "txt"_t: return "text/plain";
	case "vtt"_t: return "text/vtt";
	case "htm"_t:
	case "html"_t: return "text/html";

	case "apng"_t: return "image/apng";
	case "avif"_t: return "image/avif";
	case "bmp"_t: return "image/bmp";
	case "gif"_t: return "image/gif";
	case "png"_t: return "image/png";
	case "svg"_t: return "image/svg+xml";
	case "webp"_t: return "image/webp";
	case "ico"_t: return "image/x-icon";
	case "tif"_t: return "image/tiff";
	case "tiff"_t: return "image/tiff";
	case "jpg"_t:
	case "jpeg"_t: return "image/jpeg";

	case "mp4"_t: return "video/mp4";
	case "mpeg"_t: return "video/mpeg";
	case "webm"_t: return "video/webm";

	case "mp3"_t: return "audio/mp3";
	case "mpga"_t: return "audio/mpeg";
	case "weba"_t: return "audio/webm";
	case "wav"_t: return "audio/wave";

	case "otf"_t: return "font/otf";
	case "ttf"_t: return "font/ttf";
	case "woff"_t: return "font/woff";
	case "woff2"_t: return "font/woff2";

	case "7z"_t: return "application/x-7z-compressed";
	case "atom"_t: return "application/atom+xml";
	case "pdf"_t: return "application/pdf";
	case "js"_t:
	case "mjs"_t: return "application/javascript";
	case "json"_t: return "application/json";
	case "rss"_t: return "application/rss+xml";
	case "tar"_t: return "application/x-tar";
	case "xht"_t:
	case "xhtml"_t: return "application/xhtml+xml";
	case "xslt"_t: return "application/xslt+xml";
	case "xml"_t: return "application/xml";
	case "gz"_t: return "application/gzip";
	case "zip"_t: return "application/zip";
	case "wasm"_t: return "application/wasm";
	}
}

inline const char *status_message(int status) {
	switch (status) {
	case 100: return "Continue";
	case 101: return "Switching Protocol";
	case 102: return "Processing";
	case 103: return "Early Hints";
	case 200: return "OK";
	case 201: return "Created";
	case 202: return "Accepted";
	case 203: return "Non-Authoritative Information";
	case 204: return "No Content";
	case 205: return "Reset Content";
	case 206: return "Partial Content";
	case 207: return "Multi-Status";
	case 208: return "Already Reported";
	case 226: return "IM Used";
	case 300: return "Multiple Choice";
	case 301: return "Moved Permanently";
	case 302: return "Found";
	case 303: return "See Other";
	case 304: return "Not Modified";
	case 305: return "Use Proxy";
	case 306: return "unused";
	case 307: return "Temporary Redirect";
	case 308: return "Permanent Redirect";
	case 400: return "Bad Request";
	case 401: return "Unauthorized";
	case 402: return "Payment Required";
	case 403: return "Forbidden";
	case 404: return "Not Found";
	case 405: return "Method Not Allowed";
	case 406: return "Not Acceptable";
	case 407: return "Proxy Authentication Required";
	case 408: return "Request Timeout";
	case 409: return "Conflict";
	case 410: return "Gone";
	case 411: return "Length Required";
	case 412: return "Precondition Failed";
	case 413: return "Payload Too Large";
	case 414: return "URI Too Long";
	case 415: return "Unsupported Media Type";
	case 416: return "Range Not Satisfiable";
	case 417: return "Expectation Failed";
	case 418: return "I'm a teapot";
	case 421: return "Misdirected Request";
	case 422: return "Unprocessable Entity";
	case 423: return "Locked";
	case 424: return "Failed Dependency";
	case 425: return "Too Early";
	case 426: return "Upgrade Required";
	case 428: return "Precondition Required";
	case 429: return "Too Many Requests";
	case 431: return "Request Header Fields Too Large";
	case 451: return "Unavailable For Legal Reasons";
	case 501: return "Not Implemented";
	case 502: return "Bad Gateway";
	case 503: return "Service Unavailable";
	case 504: return "Gateway Timeout";
	case 505: return "HTTP Version Not Supported";
	case 506: return "Variant Also Negotiates";
	case 507: return "Insufficient Storage";
	case 508: return "Loop Detected";
	case 510: return "Not Extended";
	case 511: return "Network Authentication Required";

	default:
	case 500: return "Internal Server Error";
	}
}

inline bool can_compress_content_type(const std::string &content_type) {
	return (!content_type.rfind("text/", 0) &&
	        content_type != "text/event-stream") ||
	       content_type == "image/svg+xml" ||
	       content_type == "application/javascript" ||
	       content_type == "application/json" ||
	       content_type == "application/xml" ||
	       content_type == "application/protobuf" ||
	       content_type == "application/xhtml+xml";
}

inline EncodingType encoding_type(const Request &req, const Response &res) {
	auto ret =
	    detail::can_compress_content_type(res.get_header_value("Content-Type"));
	if (!ret) { return EncodingType::None; }

	const auto &s = req.get_header_value("Accept-Encoding");
	(void)(s);

#ifdef CPPHTTPLIB_BROTLI_SUPPORT
	// TODO: 'Accept-Encoding' has br, not br;q=0
	ret = s.find("br") != std::string::npos;
	if (ret) { return EncodingType::Brotli; }
#endif

#ifdef CPPHTTPLIB_ZLIB_SUPPORT
	// TODO: 'Accept-Encoding' has gzip, not gzip;q=0
	ret = s.find("gzip") != std::string::npos;
	if (ret) { return EncodingType::Gzip; }
#endif

	return EncodingType::None;
}

inline bool nocompressor::compress(const char *data, size_t data_length,
                                   bool /*last*/, Callback callback) {
	if (!data_length) { return true; }
	return callback(data, data_length);
}

#ifdef CPPHTTPLIB_ZLIB_SUPPORT
inline gzip_compressor::gzip_compressor() {
	std::memset(&strm_, 0, sizeof(strm_));
	strm_.zalloc = Z_NULL;
	strm_.zfree = Z_NULL;
	strm_.opaque = Z_NULL;

	is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
	                         Z_DEFAULT_STRATEGY) == Z_OK;
}

inline gzip_compressor::~gzip_compressor() { deflateEnd(&strm_); }

inline bool gzip_compressor::compress(const char *data, size_t data_length,
                                      bool last, Callback callback) {
	assert(is_valid_);

	do {
		constexpr size_t max_avail_in =
		    (std::numeric_limits<decltype(strm_.avail_in)>::max)();

		strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
		    (std::min)(data_length, max_avail_in));
		strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));

		data_length -= strm_.avail_in;
		data += strm_.avail_in;

		auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH;
		int ret = Z_OK;

		std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
		do {
			strm_.avail_out = static_cast<uInt>(buff.size());
			strm_.next_out = reinterpret_cast<Bytef *>(buff.data());

			ret = deflate(&strm_, flush);
			if (ret == Z_STREAM_ERROR) { return false; }

			if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
				return false;
			}
		} while (strm_.avail_out == 0);

		assert((flush == Z_FINISH && ret == Z_STREAM_END) ||
		       (flush == Z_NO_FLUSH && ret == Z_OK));
		assert(strm_.avail_in == 0);

	} while (data_length > 0);

	return true;
}

inline gzip_decompressor::gzip_decompressor() {
	std::memset(&strm_, 0, sizeof(strm_));
	strm_.zalloc = Z_NULL;
	strm_.zfree = Z_NULL;
	strm_.opaque = Z_NULL;

	// 15 is the value of wbits, which should be at the maximum possible value
	// to ensure that any gzip stream can be decoded. The offset of 32 specifies
	// that the stream type should be automatically detected either gzip or
	// deflate.
	is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK;
}

inline gzip_decompressor::~gzip_decompressor() { inflateEnd(&strm_); }

inline bool gzip_decompressor::is_valid() const { return is_valid_; }

inline bool gzip_decompressor::decompress(const char *data, size_t data_length,
                                          Callback callback) {
	assert(is_valid_);

	int ret = Z_OK;

	do {
		constexpr size_t max_avail_in =
		    (std::numeric_limits<decltype(strm_.avail_in)>::max)();

		strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
		    (std::min)(data_length, max_avail_in));
		strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));

		data_length -= strm_.avail_in;
		data += strm_.avail_in;

		std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
		while (strm_.avail_in > 0) {
			strm_.avail_out = static_cast<uInt>(buff.size());
			strm_.next_out = reinterpret_cast<Bytef *>(buff.data());

			auto prev_avail_in = strm_.avail_in;

			ret = inflate(&strm_, Z_NO_FLUSH);

			if (prev_avail_in - strm_.avail_in == 0) { return false; }

			assert(ret != Z_STREAM_ERROR);
			switch (ret) {
			case Z_NEED_DICT:
			case Z_DATA_ERROR:
			case Z_MEM_ERROR: inflateEnd(&strm_); return false;
			}

			if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
				return false;
			}
		}

		if (ret != Z_OK && ret != Z_STREAM_END) return false;

	} while (data_length > 0);

	return true;
}
#endif

#ifdef CPPHTTPLIB_BROTLI_SUPPORT
inline brotli_compressor::brotli_compressor() {
	state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
}

inline brotli_compressor::~brotli_compressor() {
	BrotliEncoderDestroyInstance(state_);
}

inline bool brotli_compressor::compress(const char *data, size_t data_length,
                                        bool last, Callback callback) {
	std::array<uint8_t, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};

	auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
	auto available_in = data_length;
	auto next_in = reinterpret_cast<const uint8_t *>(data);

	for (;;) {
		if (last) {
			if (BrotliEncoderIsFinished(state_)) { break; }
		} else {
			if (!available_in) { break; }
		}

		auto available_out = buff.size();
		auto next_out = buff.data();

		if (!BrotliEncoderCompressStream(state_, operation, &available_in, &next_in,
		                                 &available_out, &next_out, nullptr)) {
			return false;
		}

		auto output_bytes = buff.size() - available_out;
		if (output_bytes) {
			callback(reinterpret_cast<const char *>(buff.data()), output_bytes);
		}
	}

	return true;
}

inline brotli_decompressor::brotli_decompressor() {
	decoder_s = BrotliDecoderCreateInstance(0, 0, 0);
	decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT
	                      : BROTLI_DECODER_RESULT_ERROR;
}

inline brotli_decompressor::~brotli_decompressor() {
	if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); }
}

inline bool brotli_decompressor::is_valid() const { return decoder_s; }

inline bool brotli_decompressor::decompress(const char *data,
                                            size_t data_length,
                                            Callback callback) {
	if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
	    decoder_r == BROTLI_DECODER_RESULT_ERROR) {
		return 0;
	}

	const uint8_t *next_in = (const uint8_t *)data;
	size_t avail_in = data_length;
	size_t total_out;

	decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;

	std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
	while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
		char *next_out = buff.data();
		size_t avail_out = buff.size();

		decoder_r = BrotliDecoderDecompressStream(
		    decoder_s, &avail_in, &next_in, &avail_out,
		    reinterpret_cast<uint8_t **>(&next_out), &total_out);

		if (decoder_r == BROTLI_DECODER_RESULT_ERROR) { return false; }

		if (!callback(buff.data(), buff.size() - avail_out)) { return false; }
	}

	return decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
	       decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
}
#endif

inline bool has_header(const Headers &headers, const char *key) {
	return headers.find(key) != headers.end();
}

inline const char *get_header_value(const Headers &headers, const char *key,
                                    size_t id, const char *def) {
	auto rng = headers.equal_range(key);
	auto it = rng.first;
	std::advance(it, static_cast<ssize_t>(id));
	if (it != rng.second) { return it->second.c_str(); }
	return def;
}

template <typename T>
inline bool parse_header(const char *beg, const char *end, T fn) {
	// Skip trailing spaces and tabs.
	while (beg < end && is_space_or_tab(end[-1])) {
		end--;
	}

	auto p = beg;
	while (p < end && *p != ':') {
		p++;
	}

	if (p == end) { return false; }

	auto key_end = p;

	if (*p++ != ':') { return false; }

	while (p < end && is_space_or_tab(*p)) {
		p++;
	}

	if (p < end) {
		fn(std::string(beg, key_end), decode_url(std::string(p, end), false));
		return true;
	}

	return false;
}

inline bool read_headers(Stream &strm, Headers &headers) {
	const auto bufsiz = 2048;
	char buf[bufsiz];
	stream_line_reader line_reader(strm, buf, bufsiz);

	for (;;) {
		if (!line_reader.getline()) { return false; }

		// Check if the line ends with CRLF.
		auto line_terminator_len = 2;
		if (line_reader.end_with_crlf()) {
			// Blank line indicates end of headers.
			if (line_reader.size() == 2) { break; }
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
		} else {
			// Blank line indicates end of headers.
			if (line_reader.size() == 1) { break; }
			line_terminator_len = 1;
		}
#else
		} else {
			continue; // Skip invalid line.
		}
#endif

		if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }

		// Exclude line terminator
		auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;

		parse_header(line_reader.ptr(), end,
		             [&](std::string &&key, std::string &&val) {
			             headers.emplace(std::move(key), std::move(val));
		             });
	}

	return true;
}

inline bool read_content_with_length(Stream &strm, uint64_t len,
                                     Progress progress,
                                     ContentReceiverWithProgress out) {
	char buf[CPPHTTPLIB_RECV_BUFSIZ];

	uint64_t r = 0;
	while (r < len) {
		auto read_len = static_cast<size_t>(len - r);
		auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
		if (n <= 0) { return false; }

		if (!out(buf, static_cast<size_t>(n), r, len)) { return false; }
		r += static_cast<uint64_t>(n);

		if (progress) {
			if (!progress(r, len)) { return false; }
		}
	}

	return true;
}

inline void skip_content_with_length(Stream &strm, uint64_t len) {
	char buf[CPPHTTPLIB_RECV_BUFSIZ];
	uint64_t r = 0;
	while (r < len) {
		auto read_len = static_cast<size_t>(len - r);
		auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
		if (n <= 0) { return; }
		r += static_cast<uint64_t>(n);
	}
}

inline bool read_content_without_length(Stream &strm,
                                        ContentReceiverWithProgress out) {
	char buf[CPPHTTPLIB_RECV_BUFSIZ];
	uint64_t r = 0;
	for (;;) {
		auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ);
		if (n < 0) {
			return false;
		} else if (n == 0) {
			return true;
		}

		if (!out(buf, static_cast<size_t>(n), r, 0)) { return false; }
		r += static_cast<uint64_t>(n);
	}

	return true;
}

inline bool read_content_chunked(Stream &strm,
                                 ContentReceiverWithProgress out) {
	const auto bufsiz = 16;
	char buf[bufsiz];

	stream_line_reader line_reader(strm, buf, bufsiz);

	if (!line_reader.getline()) { return false; }

	unsigned long chunk_len;
	while (true) {
		char *end_ptr;

		chunk_len = std::strtoul(line_reader.ptr(), &end_ptr, 16);

		if (end_ptr == line_reader.ptr()) { return false; }
		if (chunk_len == ULONG_MAX) { return false; }

		if (chunk_len == 0) { break; }

		if (!read_content_with_length(strm, chunk_len, nullptr, out)) {
			return false;
		}

		if (!line_reader.getline()) { return false; }

		if (strcmp(line_reader.ptr(), "\r\n")) { break; }

		if (!line_reader.getline()) { return false; }
	}

	if (chunk_len == 0) {
		// Reader terminator after chunks
		if (!line_reader.getline() || strcmp(line_reader.ptr(), "\r\n"))
			return false;
	}

	return true;
}

inline bool is_chunked_transfer_encoding(const Headers &headers) {
	return !strcasecmp(get_header_value(headers, "Transfer-Encoding", 0, ""),
	                   "chunked");
}

template <typename T, typename U>
bool prepare_content_receiver(T &x, int &status,
                              ContentReceiverWithProgress receiver,
                              bool decompress, U callback) {
	if (decompress) {
		std::string encoding = x.get_header_value("Content-Encoding");
		std::unique_ptr<decompressor> decompressor;

		if (encoding == "gzip" || encoding == "deflate") {
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
			decompressor = detail::make_unique<gzip_decompressor>();
#else
			status = 415;
			return false;
#endif
		} else if (encoding.find("br") != std::string::npos) {
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
			decompressor = detail::make_unique<brotli_decompressor>();
#else
			status = 415;
			return false;
#endif
		}

		if (decompressor) {
			if (decompressor->is_valid()) {
				ContentReceiverWithProgress out = [&](const char *buf, size_t n,
				                                      uint64_t off, uint64_t len) {
					return decompressor->decompress(buf, n,
					                                [&](const char *buf2, size_t n2) {
						                                return receiver(buf2, n2, off, len);
					                                });
				};
				return callback(std::move(out));
			} else {
				status = 500;
				return false;
			}
		}
	}

	ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off,
	                                      uint64_t len) {
		return receiver(buf, n, off, len);
	};
	return callback(std::move(out));
}

template <typename T>
bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
                  Progress progress, ContentReceiverWithProgress receiver,
                  bool decompress) {
	return prepare_content_receiver(
	    x, status, std::move(receiver), decompress,
	    [&](const ContentReceiverWithProgress &out) {
		    auto ret = true;
		    auto exceed_payload_max_length = false;

		    if (is_chunked_transfer_encoding(x.headers)) {
			    ret = read_content_chunked(strm, out);
		    } else if (!has_header(x.headers, "Content-Length")) {
			    ret = read_content_without_length(strm, out);
		    } else {
			    auto len = get_header_value<uint64_t>(x.headers, "Content-Length");
			    if (len > payload_max_length) {
				    exceed_payload_max_length = true;
				    skip_content_with_length(strm, len);
				    ret = false;
			    } else if (len > 0) {
				    ret = read_content_with_length(strm, len, std::move(progress), out);
			    }
		    }

		    if (!ret) { status = exceed_payload_max_length ? 413 : 400; }
		    return ret;
	    });
}

inline ssize_t write_headers(Stream &strm, const Headers &headers) {
	ssize_t write_len = 0;
	for (const auto &x : headers) {
		auto len =
		    strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str());
		if (len < 0) { return len; }
		write_len += len;
	}
	auto len = strm.write("\r\n");
	if (len < 0) { return len; }
	write_len += len;
	return write_len;
}

inline bool write_data(Stream &strm, const char *d, size_t l) {
	size_t offset = 0;
	while (offset < l) {
		auto length = strm.write(d + offset, l - offset);
		if (length < 0) { return false; }
		offset += static_cast<size_t>(length);
	}
	return true;
}

template <typename T>
inline bool write_content(Stream &strm, const ContentProvider &content_provider,
                          size_t offset, size_t length, T is_shutting_down,
                          Error &error) {
	size_t end_offset = offset + length;
	auto ok = true;
	DataSink data_sink;

	data_sink.write = [&](const char *d, size_t l) -> bool {
		if (ok) {
			if (write_data(strm, d, l)) {
				offset += l;
			} else {
				ok = false;
			}
		}
		return ok;
	};

	data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };

	while (offset < end_offset && !is_shutting_down()) {
		if (!content_provider(offset, end_offset - offset, data_sink)) {
			error = Error::Canceled;
			return false;
		}
		if (!ok) {
			error = Error::Write;
			return false;
		}
	}

	error = Error::Success;
	return true;
}

template <typename T>
inline bool write_content(Stream &strm, const ContentProvider &content_provider,
                          size_t offset, size_t length,
                          const T &is_shutting_down) {
	auto error = Error::Success;
	return write_content(strm, content_provider, offset, length, is_shutting_down,
	                     error);
}

template <typename T>
inline bool
write_content_without_length(Stream &strm,
                             const ContentProvider &content_provider,
                             const T &is_shutting_down) {
	size_t offset = 0;
	auto data_available = true;
	auto ok = true;
	DataSink data_sink;

	data_sink.write = [&](const char *d, size_t l) -> bool {
		if (ok) {
			offset += l;
			if (!write_data(strm, d, l)) { ok = false; }
		}
		return ok;
	};

	data_sink.done = [&](void) { data_available = false; };

	data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };

	while (data_available && !is_shutting_down()) {
		if (!content_provider(offset, 0, data_sink)) { return false; }
		if (!ok) { return false; }
	}
	return true;
}

template <typename T, typename U>
inline bool
write_content_chunked(Stream &strm, const ContentProvider &content_provider,
                      const T &is_shutting_down, U &compressor, Error &error) {
	size_t offset = 0;
	auto data_available = true;
	auto ok = true;
	DataSink data_sink;

	data_sink.write = [&](const char *d, size_t l) -> bool {
		if (ok) {
			data_available = l > 0;
			offset += l;

			std::string payload;
			if (compressor.compress(d, l, false,
			                        [&](const char *data, size_t data_len) {
				                        payload.append(data, data_len);
				                        return true;
			                        })) {
				if (!payload.empty()) {
					// Emit chunked response header and footer for each chunk
					auto chunk =
					    from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
					if (!write_data(strm, chunk.data(), chunk.size())) { ok = false; }
				}
			} else {
				ok = false;
			}
		}
		return ok;
	};

	data_sink.done = [&](void) {
		if (!ok) { return; }

		data_available = false;

		std::string payload;
		if (!compressor.compress(nullptr, 0, true,
		                         [&](const char *data, size_t data_len) {
			                         payload.append(data, data_len);
			                         return true;
		                         })) {
			ok = false;
			return;
		}

		if (!payload.empty()) {
			// Emit chunked response header and footer for each chunk
			auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
			if (!write_data(strm, chunk.data(), chunk.size())) {
				ok = false;
				return;
			}
		}

		static const std::string done_marker("0\r\n\r\n");
		if (!write_data(strm, done_marker.data(), done_marker.size())) {
			ok = false;
		}
	};

	data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };

	while (data_available && !is_shutting_down()) {
		if (!content_provider(offset, 0, data_sink)) {
			error = Error::Canceled;
			return false;
		}
		if (!ok) {
			error = Error::Write;
			return false;
		}
	}

	error = Error::Success;
	return true;
}

template <typename T, typename U>
inline bool write_content_chunked(Stream &strm,
                                  const ContentProvider &content_provider,
                                  const T &is_shutting_down, U &compressor) {
	auto error = Error::Success;
	return write_content_chunked(strm, content_provider, is_shutting_down,
	                             compressor, error);
}

template <typename T>
inline bool redirect(T &cli, Request &req, Response &res,
                     const std::string &path, const std::string &location,
                     Error &error) {
	Request new_req = req;
	new_req.path = path;
	new_req.redirect_count_ -= 1;

	if (res.status == 303 && (req.method != "GET" && req.method != "HEAD")) {
		new_req.method = "GET";
		new_req.body.clear();
		new_req.headers.clear();
	}

	Response new_res;

	auto ret = cli.send(new_req, new_res, error);
	if (ret) {
		req = new_req;
		res = new_res;
		res.location = location;
	}
	return ret;
}

inline std::string params_to_query_str(const Params &params) {
	std::string query;

	for (auto it = params.begin(); it != params.end(); ++it) {
		if (it != params.begin()) { query += "&"; }
		query += it->first;
		query += "=";
		query += encode_query_param(it->second);
	}
	return query;
}

inline void parse_query_text(const std::string &s, Params &params) {
	std::set<std::string> cache;
	split(s.data(), s.data() + s.size(), '&', [&](const char *b, const char *e) {
		std::string kv(b, e);
		if (cache.find(kv) != cache.end()) { return; }
		cache.insert(kv);

		std::string key;
		std::string val;
		split(b, e, '=', [&](const char *b2, const char *e2) {
			if (key.empty()) {
				key.assign(b2, e2);
			} else {
				val.assign(b2, e2);
			}
		});

		if (!key.empty()) {
			params.emplace(decode_url(key, true), decode_url(val, false));
		}
	});
}

inline bool parse_multipart_boundary(const std::string &content_type,
                                     std::string &boundary) {
	auto pos = content_type.find("boundary=");
	if (pos == std::string::npos) { return false; }
	boundary = content_type.substr(pos + 9);
	if (boundary.length() >= 2 && boundary.front() == '"' &&
	    boundary.back() == '"') {
		boundary = boundary.substr(1, boundary.size() - 2);
	}
	return !boundary.empty();
}

#ifdef CPPHTTPLIB_NO_EXCEPTIONS
inline bool parse_range_header(const std::string &s, Ranges &ranges) {
#else
inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
#endif
	static Regex re_first_range(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))");
	Match m;
	if (duckdb_re2::RegexMatch(s, m, re_first_range)) {
		auto pos = static_cast<size_t>(m.position(1));
		auto len = static_cast<size_t>(m.length(1));
		bool all_valid_ranges = true;
		split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
			if (!all_valid_ranges) return;
			static Regex re_another_range(R"(\s*(\d*)-(\d*))");
			Match cm;
			if (duckdb_re2::RegexMatch(b, e, cm, re_another_range)) {
				ssize_t first = -1;
				if (!cm.str(1).empty()) {
					first = static_cast<ssize_t>(std::stoll(cm.str(1)));
				}

				ssize_t last = -1;
				if (!cm.str(2).empty()) {
					last = static_cast<ssize_t>(std::stoll(cm.str(2)));
				}

				if (first != -1 && last != -1 && first > last) {
					all_valid_ranges = false;
					return;
				}
				ranges.emplace_back(std::make_pair(first, last));
			}
		});
		return all_valid_ranges;
	}
	return false;
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
}
#else
} catch (...) { return false; }
#endif

class MultipartFormDataParser {
public:
	MultipartFormDataParser() = default;

	void set_boundary(std::string &&boundary) { boundary_ = boundary; }

	bool is_valid() const { return is_valid_; }

	bool parse(const char *buf, size_t n, const ContentReceiver &content_callback,
	           const MultipartContentHeader &header_callback) {

		static const Regex re_content_disposition(
		    "^Content-Disposition:\\s*form-data;\\s*name=\"(.*?)\"(?:;\\s*filename="
		    "\"(.*?)\")?\\s*$",
		    duckdb_re2::RegexOptions::CASE_INSENSITIVE);
		static const std::string dash_ = "--";
		static const std::string crlf_ = "\r\n";

		buf_append(buf, n);

		while (buf_size() > 0) {
			switch (state_) {
			case 0: { // Initial boundary
				auto pattern = dash_ + boundary_ + crlf_;
				if (pattern.size() > buf_size()) { return true; }
				if (!buf_start_with(pattern)) { return false; }
				buf_erase(pattern.size());
				state_ = 1;
				break;
			}
			case 1: { // New entry
				clear_file_info();
				state_ = 2;
				break;
			}
			case 2: { // Headers
				auto pos = buf_find(crlf_);
				if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
				while (pos < buf_size()) {
					// Empty line
					if (pos == 0) {
						if (!header_callback(file_)) {
							is_valid_ = false;
							return false;
						}
						buf_erase(crlf_.size());
						state_ = 3;
						break;
					}

					static const std::string header_name = "content-type:";
					const auto header = buf_head(pos);
					if (start_with_case_ignore(header, header_name)) {
						file_.content_type = trim_copy(header.substr(header_name.size()));
					} else {
						Match m;
						if (duckdb_re2::RegexMatch(header, m, re_content_disposition)) {
							file_.name = m[1];
							file_.filename = m[2];
						}
					}

					buf_erase(pos + crlf_.size());
					pos = buf_find(crlf_);
				}
				if (state_ != 3) { return true; }
				break;
			}
			case 3: { // Body
				{
					auto pattern = crlf_ + dash_;
					if (pattern.size() > buf_size()) { return true; }

					auto pos = buf_find(pattern);

					if (!content_callback(buf_data(), pos)) {
						is_valid_ = false;
						return false;
					}

					buf_erase(pos);
				}
				{
					auto pattern = crlf_ + dash_ + boundary_;
					if (pattern.size() > buf_size()) { return true; }

					auto pos = buf_find(pattern);
					if (pos < buf_size()) {
						if (!content_callback(buf_data(), pos)) {
							is_valid_ = false;
							return false;
						}

						buf_erase(pos + pattern.size());
						state_ = 4;
					} else {
						if (!content_callback(buf_data(), pattern.size())) {
							is_valid_ = false;
							return false;
						}

						buf_erase(pattern.size());
					}
				}
				break;
			}
			case 4: { // Boundary
				if (crlf_.size() > buf_size()) { return true; }
				if (buf_start_with(crlf_)) {
					buf_erase(crlf_.size());
					state_ = 1;
				} else {
					auto pattern = dash_ + crlf_;
					if (pattern.size() > buf_size()) { return true; }
					if (buf_start_with(pattern)) {
						buf_erase(pattern.size());
						is_valid_ = true;
						state_ = 5;
					} else {
						return true;
					}
				}
				break;
			}
			case 5: { // Done
				is_valid_ = false;
				return false;
			}
			}
		}

		return true;
	}

private:
	void clear_file_info() {
		file_.name.clear();
		file_.filename.clear();
		file_.content_type.clear();
	}

	bool start_with_case_ignore(const std::string &a,
	                            const std::string &b) const {
		if (a.size() < b.size()) { return false; }
		for (size_t i = 0; i < b.size(); i++) {
			if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
		}
		return true;
	}

	std::string boundary_;

	size_t state_ = 0;
	bool is_valid_ = false;
	MultipartFormData file_;

	// Buffer
	bool start_with(const std::string &a, size_t spos, size_t epos,
	                const std::string &b) const {
		if (epos - spos < b.size()) { return false; }
		for (size_t i = 0; i < b.size(); i++) {
			if (a[i + spos] != b[i]) { return false; }
		}
		return true;
	}

	size_t buf_size() const { return buf_epos_ - buf_spos_; }

	const char *buf_data() const { return &buf_[buf_spos_]; }

	std::string buf_head(size_t l) const { return buf_.substr(buf_spos_, l); }

	bool buf_start_with(const std::string &s) const {
		return start_with(buf_, buf_spos_, buf_epos_, s);
	}

	size_t buf_find(const std::string &s) const {
		auto c = s.front();

		size_t off = buf_spos_;
		while (off < buf_epos_) {
			auto pos = off;
			while (true) {
				if (pos == buf_epos_) { return buf_size(); }
				if (buf_[pos] == c) { break; }
				pos++;
			}

			auto remaining_size = buf_epos_ - pos;
			if (s.size() > remaining_size) { return buf_size(); }

			if (start_with(buf_, pos, buf_epos_, s)) { return pos - buf_spos_; }

			off = pos + 1;
		}

		return buf_size();
	}

	void buf_append(const char *data, size_t n) {
		auto remaining_size = buf_size();
		if (remaining_size > 0 && buf_spos_ > 0) {
			for (size_t i = 0; i < remaining_size; i++) {
				buf_[i] = buf_[buf_spos_ + i];
			}
		}
		buf_spos_ = 0;
		buf_epos_ = remaining_size;

		if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); }

		for (size_t i = 0; i < n; i++) {
			buf_[buf_epos_ + i] = data[i];
		}
		buf_epos_ += n;
	}

	void buf_erase(size_t size) { buf_spos_ += size; }

	std::string buf_;
	size_t buf_spos_ = 0;
	size_t buf_epos_ = 0;
};

inline std::string to_lower(const char *beg, const char *end) {
	std::string out;
	auto it = beg;
	while (it != end) {
		out += static_cast<char>(::tolower(*it));
		it++;
	}
	return out;
}

inline std::string make_multipart_data_boundary() {
	static const char data[] =
	    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

	// std::random_device might actually be deterministic on some
	// platforms, but due to lack of support in the c++ standard library,
	// doing better requires either some ugly hacks or breaking portability.
	std::random_device seed_gen;

	// Request 128 bits of entropy for initialization
	std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()};
	std::mt19937 engine(seed_sequence);

	std::string result = "--cpp-httplib-multipart-data-";

	for (auto i = 0; i < 16; i++) {
		result += data[engine() % (sizeof(data) - 1)];
	}

	return result;
}

inline std::pair<size_t, size_t>
get_range_offset_and_length(const Request &req, size_t content_length,
                            size_t index) {
	auto r = req.ranges[index];

	if (r.first == -1 && r.second == -1) {
		return std::make_pair(0, content_length);
	}

	auto slen = static_cast<ssize_t>(content_length);

	if (r.first == -1) {
		r.first = (std::max)(static_cast<ssize_t>(0), slen - r.second);
		r.second = slen - 1;
	}

	if (r.second == -1) { r.second = slen - 1; }
	return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
}

inline std::string make_content_range_header_field(size_t offset, size_t length,
                                                   size_t content_length) {
	std::string field = "bytes ";
	field += std::to_string(offset);
	field += "-";
	field += std::to_string(offset + length - 1);
	field += "/";
	field += std::to_string(content_length);
	return field;
}

template <typename SToken, typename CToken, typename Content>
bool process_multipart_ranges_data(const Request &req, Response &res,
                                   const std::string &boundary,
                                   const std::string &content_type,
                                   SToken stoken, CToken ctoken,
                                   Content content) {
	for (size_t i = 0; i < req.ranges.size(); i++) {
		ctoken("--");
		stoken(boundary);
		ctoken("\r\n");
		if (!content_type.empty()) {
			ctoken("Content-Type: ");
			stoken(content_type);
			ctoken("\r\n");
		}

		auto offsets = get_range_offset_and_length(req, res.body.size(), i);
		auto offset = offsets.first;
		auto length = offsets.second;

		ctoken("Content-Range: ");
		stoken(make_content_range_header_field(offset, length, res.body.size()));
		ctoken("\r\n");
		ctoken("\r\n");
		if (!content(offset, length)) { return false; }
		ctoken("\r\n");
	}

	ctoken("--");
	stoken(boundary);
	ctoken("--\r\n");

	return true;
}

inline bool make_multipart_ranges_data(const Request &req, Response &res,
                                       const std::string &boundary,
                                       const std::string &content_type,
                                       std::string &data) {
	return process_multipart_ranges_data(
	    req, res, boundary, content_type,
	    [&](const std::string &token) { data += token; },
	    [&](const char *token) { data += token; },
	    [&](size_t offset, size_t length) {
		    if (offset < res.body.size()) {
			    data += res.body.substr(offset, length);
			    return true;
		    }
		    return false;
	    });
}

inline size_t
get_multipart_ranges_data_length(const Request &req, Response &res,
                                 const std::string &boundary,
                                 const std::string &content_type) {
	size_t data_length = 0;

	process_multipart_ranges_data(
	    req, res, boundary, content_type,
	    [&](const std::string &token) { data_length += token.size(); },
	    [&](const char *token) { data_length += strlen(token); },
	    [&](size_t /*offset*/, size_t length) {
		    data_length += length;
		    return true;
	    });

	return data_length;
}

template <typename T>
inline bool write_multipart_ranges_data(Stream &strm, const Request &req,
                                        Response &res,
                                        const std::string &boundary,
                                        const std::string &content_type,
                                        const T &is_shutting_down) {
	return process_multipart_ranges_data(
	    req, res, boundary, content_type,
	    [&](const std::string &token) { strm.write(token); },
	    [&](const char *token) { strm.write(token); },
	    [&](size_t offset, size_t length) {
		    return write_content(strm, res.content_provider_, offset, length,
		                         is_shutting_down);
	    });
}

inline std::pair<size_t, size_t>
get_range_offset_and_length(const Request &req, const Response &res,
                            size_t index) {
	auto r = req.ranges[index];

	if (r.second == -1) {
		r.second = static_cast<ssize_t>(res.content_length_) - 1;
	}

	return std::make_pair(r.first, r.second - r.first + 1);
}

inline bool expect_content(const Request &req) {
	if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
	    req.method == "PRI" || req.method == "DELETE") {
		return true;
	}
	// TODO: check if Content-Length is set
	return false;
}

inline bool has_crlf(const char *s) {
	auto p = s;
	while (*p) {
		if (*p == '\r' || *p == '\n') { return true; }
		p++;
	}
	return false;
}

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
template <typename CTX, typename Init, typename Update, typename Final>
inline std::string message_digest(const std::string &s, Init init,
                                  Update update, Final final,
                                  size_t digest_length) {
	std::vector<unsigned char> md(digest_length, 0);
	CTX ctx;
	init(&ctx);
	update(&ctx, s.data(), s.size());
	final(md.data(), &ctx);

	std::stringstream ss;
	for (auto c : md) {
		ss << std::setfill('0') << std::setw(2) << std::hex << (unsigned int)c;
	}
	return ss.str();
}

inline std::string MD5(const std::string &s) {
	return message_digest<MD5_CTX>(s, MD5_Init, MD5_Update, MD5_Final,
	                               MD5_DIGEST_LENGTH);
}

inline std::string SHA_256(const std::string &s) {
	return message_digest<SHA256_CTX>(s, SHA256_Init, SHA256_Update, SHA256_Final,
	                                  SHA256_DIGEST_LENGTH);
}

inline std::string SHA_512(const std::string &s) {
	return message_digest<SHA512_CTX>(s, SHA512_Init, SHA512_Update, SHA512_Final,
	                                  SHA512_DIGEST_LENGTH);
}
#endif

#ifdef _WIN32
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
// NOTE: This code came up with the following stackoverflow post:
// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
inline bool load_system_certs_on_windows(X509_STORE *store) {
	auto hStore = CertOpenSystemStoreW((HCRYPTPROV_LEGACY)NULL, L"ROOT");

	if (!hStore) { return false; }

	PCCERT_CONTEXT pContext = NULL;
	while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) !=
	       nullptr) {
		auto encoded_cert =
		    static_cast<const unsigned char *>(pContext->pbCertEncoded);

		auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
		if (x509) {
			X509_STORE_add_cert(store, x509);
			X509_free(x509);
		}
	}

	CertFreeCertificateContext(pContext);
	CertCloseStore(hStore, 0);

	return true;
}
#endif

class WSInit {
public:
	WSInit() {
		WSADATA wsaData;
		WSAStartup(0x0002, &wsaData);
	}

	~WSInit() { WSACleanup(); }
};

static WSInit wsinit_;
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline std::pair<std::string, std::string> make_digest_authentication_header(
    const Request &req, const std::map<std::string, std::string> &auth,
    size_t cnonce_count, const std::string &cnonce, const std::string &username,
    const std::string &password, bool is_proxy = false) {
	std::string nc;
	{
		std::stringstream ss;
		ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count;
		nc = ss.str();
	}

	std::string qop;
	if (auth.find("qop") != auth.end()) {
		qop = auth.at("qop");
		if (qop.find("auth-int") != std::string::npos) {
			qop = "auth-int";
		} else if (qop.find("auth") != std::string::npos) {
			qop = "auth";
		} else {
			qop.clear();
		}
	}

	std::string algo = "MD5";
	if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); }

	std::string response;
	{
		auto H = algo == "SHA-256"   ? detail::SHA_256
		         : algo == "SHA-512" ? detail::SHA_512
		                             : detail::MD5;

		auto A1 = username + ":" + auth.at("realm") + ":" + password;

		auto A2 = req.method + ":" + req.path;
		if (qop == "auth-int") { A2 += ":" + H(req.body); }

		if (qop.empty()) {
			response = H(H(A1) + ":" + auth.at("nonce") + ":" + H(A2));
		} else {
			response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce +
			             ":" + qop + ":" + H(A2));
		}
	}

	auto opaque = (auth.find("opaque") != auth.end()) ? auth.at("opaque") : "";

	auto field = "Digest username=\"" + username + "\", realm=\"" +
	             auth.at("realm") + "\", nonce=\"" + auth.at("nonce") +
	             "\", uri=\"" + req.path + "\", algorithm=" + algo +
	             (qop.empty() ? ", response=\""
	                          : ", qop=" + qop + ", nc=" + nc + ", cnonce=\"" +
	                                cnonce + "\", response=\"") +
	             response + "\"" +
	             (opaque.empty() ? "" : ", opaque=\"" + opaque + "\"");

	auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
	return std::make_pair(key, field);
}
#endif

inline bool parse_www_authenticate(const Response &res,
                                   std::map<std::string, std::string> &auth,
                                   bool is_proxy) {
	auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
	if (res.has_header(auth_key)) {
		static Regex re(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
		auto s = res.get_header_value(auth_key);
		auto pos = s.find(' ');
		if (pos != std::string::npos) {
			auto type = s.substr(0, pos);
			if (type == "Basic") {
				return false;
			} else if (type == "Digest") {
				s = s.substr(pos + 1);
				auto matches = duckdb_re2::RegexFindAll(s, re);
				for (auto &m : matches) {
					auto key = s.substr(static_cast<size_t>(m.position(1)),
					                    static_cast<size_t>(m.length(1)));
					auto val = m.length(2) > 0
					               ? s.substr(static_cast<size_t>(m.position(2)),
					                          static_cast<size_t>(m.length(2)))
					               : s.substr(static_cast<size_t>(m.position(3)),
					                          static_cast<size_t>(m.length(3)));
					auth[key] = val;
				}
				return true;
			}
		}
	}
	return false;
}

// https://stackoverflow.com/questions/440133/how-do-i-create-a-random-alpha-numeric-string-in-c/440240#answer-440240
inline std::string random_string(size_t length) {
	auto randchar = []() -> char {
		const char charset[] = "0123456789"
		                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		                       "abcdefghijklmnopqrstuvwxyz";
		const size_t max_index = (sizeof(charset) - 1);
		return charset[static_cast<size_t>(std::rand()) % max_index];
	};
	std::string str(length, 0);
	std::generate_n(str.begin(), length, randchar);
	return str;
}

class ContentProviderAdapter {
public:
	explicit ContentProviderAdapter(
	    ContentProviderWithoutLength &&content_provider)
	    : content_provider_(content_provider) {}

	bool operator()(size_t offset, size_t, DataSink &sink) {
		return content_provider_(offset, sink);
	}

private:
	ContentProviderWithoutLength content_provider_;
};

} // namespace detail

inline std::string hosted_at(const char *hostname) {
	std::vector<std::string> addrs;
	hosted_at(hostname, addrs);
	if (addrs.empty()) { return std::string(); }
	return addrs[0];
}

inline void hosted_at(const char *hostname, std::vector<std::string> &addrs) {
	struct addrinfo hints;
	struct addrinfo *result;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;

	if (getaddrinfo(hostname, nullptr, &hints, &result)) {
#if defined __linux__ && !defined __ANDROID__
		res_init();
#endif
		return;
	}

	for (auto rp = result; rp; rp = rp->ai_next) {
		const auto &addr =
		    *reinterpret_cast<struct sockaddr_storage *>(rp->ai_addr);
		std::string ip;
		int dummy = -1;
		if (detail::get_remote_ip_and_port(addr, sizeof(struct sockaddr_storage),
		                                   ip, dummy)) {
			addrs.push_back(ip);
		}
	}
}

inline std::string append_query_params(const char *path, const Params &params) {
	std::string path_with_query = path;
	const static Regex re("[^?]+\\?.*");
	auto delm = duckdb_re2::RegexMatch(path, re) ? '&' : '?';
	path_with_query += delm + detail::params_to_query_str(params);
	return path_with_query;
}

// Header utilities
inline std::pair<std::string, std::string> make_range_header(Ranges ranges) {
	std::string field = "bytes=";
	auto i = 0;
	for (auto r : ranges) {
		if (i != 0) { field += ", "; }
		if (r.first != -1) { field += std::to_string(r.first); }
		field += '-';
		if (r.second != -1) { field += std::to_string(r.second); }
		i++;
	}
	return std::make_pair("Range", std::move(field));
}

inline std::pair<std::string, std::string>
make_basic_authentication_header(const std::string &username,
                                 const std::string &password, bool is_proxy) {
	auto field = "Basic " + detail::base64_encode(username + ":" + password);
	auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
	return std::make_pair(key, std::move(field));
}

inline std::pair<std::string, std::string>
make_bearer_token_authentication_header(const std::string &token,
                                        bool is_proxy = false) {
	auto field = "Bearer " + token;
	auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
	return std::make_pair(key, std::move(field));
}

// Request implementation
inline bool Request::has_header(const char *key) const {
	return detail::has_header(headers, key);
}

inline std::string Request::get_header_value(const char *key, size_t id) const {
	return detail::get_header_value(headers, key, id, "");
}

inline size_t Request::get_header_value_count(const char *key) const {
	auto r = headers.equal_range(key);
	return static_cast<size_t>(std::distance(r.first, r.second));
}

inline void Request::set_header(const char *key, const char *val) {
	if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
		headers.emplace(key, val);
	}
}

inline void Request::set_header(const char *key, const std::string &val) {
	if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
		headers.emplace(key, val);
	}
}

inline bool Request::has_param(const char *key) const {
	return params.find(key) != params.end();
}

inline std::string Request::get_param_value(const char *key, size_t id) const {
	auto rng = params.equal_range(key);
	auto it = rng.first;
	std::advance(it, static_cast<ssize_t>(id));
	if (it != rng.second) { return it->second; }
	return std::string();
}

inline size_t Request::get_param_value_count(const char *key) const {
	auto r = params.equal_range(key);
	return static_cast<size_t>(std::distance(r.first, r.second));
}

inline bool Request::is_multipart_form_data() const {
	const auto &content_type = get_header_value("Content-Type");
	return !content_type.rfind("multipart/form-data", 0);
}

inline bool Request::has_file(const char *key) const {
	return files.find(key) != files.end();
}

inline MultipartFormData Request::get_file_value(const char *key) const {
	auto it = files.find(key);
	if (it != files.end()) { return it->second; }
	return MultipartFormData();
}

// Response implementation
inline bool Response::has_header(const char *key) const {
	return headers.find(key) != headers.end();
}

inline std::string Response::get_header_value(const char *key,
                                              size_t id) const {
	return detail::get_header_value(headers, key, id, "");
}

inline size_t Response::get_header_value_count(const char *key) const {
	auto r = headers.equal_range(key);
	return static_cast<size_t>(std::distance(r.first, r.second));
}

inline void Response::set_header(const char *key, const char *val) {
	if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
		headers.emplace(key, val);
	}
}

inline void Response::set_header(const char *key, const std::string &val) {
	if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
		headers.emplace(key, val);
	}
}

inline void Response::set_redirect(const char *url, int stat) {
	if (!detail::has_crlf(url)) {
		set_header("Location", url);
		if (300 <= stat && stat < 400) {
			this->status = stat;
		} else {
			this->status = 302;
		}
	}
}

inline void Response::set_redirect(const std::string &url, int stat) {
	set_redirect(url.c_str(), stat);
}

inline void Response::set_content(const char *s, size_t n,
                                  const char *content_type) {
	body.assign(s, n);

	auto rng = headers.equal_range("Content-Type");
	headers.erase(rng.first, rng.second);
	set_header("Content-Type", content_type);
}

inline void Response::set_content(const std::string &s,
                                  const char *content_type) {
	set_content(s.data(), s.size(), content_type);
}

inline void Response::set_content_provider(
    size_t in_length, const char *content_type, ContentProvider provider,
    ContentProviderResourceReleaser resource_releaser) {
	assert(in_length > 0);
	set_header("Content-Type", content_type);
	content_length_ = in_length;
	content_provider_ = std::move(provider);
	content_provider_resource_releaser_ = resource_releaser;
	is_chunked_content_provider_ = false;
}

inline void Response::set_content_provider(
    const char *content_type, ContentProviderWithoutLength provider,
    ContentProviderResourceReleaser resource_releaser) {
	set_header("Content-Type", content_type);
	content_length_ = 0;
	content_provider_ = detail::ContentProviderAdapter(std::move(provider));
	content_provider_resource_releaser_ = resource_releaser;
	is_chunked_content_provider_ = false;
}

inline void Response::set_chunked_content_provider(
    const char *content_type, ContentProviderWithoutLength provider,
    ContentProviderResourceReleaser resource_releaser) {
	set_header("Content-Type", content_type);
	content_length_ = 0;
	content_provider_ = detail::ContentProviderAdapter(std::move(provider));
	content_provider_resource_releaser_ = resource_releaser;
	is_chunked_content_provider_ = true;
}

// Result implementation
inline bool Result::has_request_header(const char *key) const {
	return request_headers_.find(key) != request_headers_.end();
}

inline std::string Result::get_request_header_value(const char *key,
                                                    size_t id) const {
	return detail::get_header_value(request_headers_, key, id, "");
}

inline size_t Result::get_request_header_value_count(const char *key) const {
	auto r = request_headers_.equal_range(key);
	return static_cast<size_t>(std::distance(r.first, r.second));
}

// Stream implementation
inline ssize_t Stream::write(const char *ptr) {
	return write(ptr, strlen(ptr));
}

inline ssize_t Stream::write(const std::string &s) {
	return write(s.data(), s.size());
}

namespace detail {

// Socket stream implementation
inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
                                  time_t read_timeout_usec,
                                  time_t write_timeout_sec,
                                  time_t write_timeout_usec)
    : sock_(sock), read_timeout_sec_(read_timeout_sec),
      read_timeout_usec_(read_timeout_usec),
      write_timeout_sec_(write_timeout_sec),
      write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {}

inline SocketStream::~SocketStream() {}

inline bool SocketStream::is_readable() const {
	return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
}

inline bool SocketStream::is_writable() const {
	return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0;
}

inline ssize_t SocketStream::read(char *ptr, size_t size) {
#ifdef _WIN32
	size =
	    (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
#else
	size = (std::min)(size,
	                  static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
#endif

	if (read_buff_off_ < read_buff_content_size_) {
		auto remaining_size = read_buff_content_size_ - read_buff_off_;
		if (size <= remaining_size) {
			memcpy(ptr, read_buff_.data() + read_buff_off_, size);
			read_buff_off_ += size;
			return static_cast<ssize_t>(size);
		} else {
			memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size);
			read_buff_off_ += remaining_size;
			return static_cast<ssize_t>(remaining_size);
		}
	}

	if (!is_readable()) { return -1; }

	read_buff_off_ = 0;
	read_buff_content_size_ = 0;

	if (size < read_buff_size_) {
		auto n = read_socket(sock_, read_buff_.data(), read_buff_size_,
		                     CPPHTTPLIB_RECV_FLAGS);
		if (n <= 0) {
			return n;
		} else if (n <= static_cast<ssize_t>(size)) {
			memcpy(ptr, read_buff_.data(), static_cast<size_t>(n));
			return n;
		} else {
			memcpy(ptr, read_buff_.data(), size);
			read_buff_off_ = size;
			read_buff_content_size_ = static_cast<size_t>(n);
			return static_cast<ssize_t>(size);
		}
	} else {
		return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS);
	}
}

inline ssize_t SocketStream::write(const char *ptr, size_t size) {
	if (!is_writable()) { return -1; }

#ifdef _WIN32
	size =
	    (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
#endif

	return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS);
}

inline void SocketStream::get_remote_ip_and_port(std::string &ip,
                                                 int &port) const {
	return detail::get_remote_ip_and_port(sock_, ip, port);
}

inline socket_t SocketStream::socket() const { return sock_; }

// Buffer stream implementation
inline bool BufferStream::is_readable() const { return true; }

inline bool BufferStream::is_writable() const { return true; }

inline ssize_t BufferStream::read(char *ptr, size_t size) {
#if defined(_MSC_VER) && _MSC_VER <= 1900
	auto len_read = buffer._Copy_s(ptr, size, size, position);
#else
	auto len_read = buffer.copy(ptr, size, position);
#endif
	position += static_cast<size_t>(len_read);
	return static_cast<ssize_t>(len_read);
}

inline ssize_t BufferStream::write(const char *ptr, size_t size) {
	buffer.append(ptr, size);
	return static_cast<ssize_t>(size);
}

inline void BufferStream::get_remote_ip_and_port(std::string & /*ip*/,
                                                 int & /*port*/) const {}

inline socket_t BufferStream::socket() const { return 0; }

inline const std::string &BufferStream::get_buffer() const { return buffer; }

} // namespace detail

// HTTP server implementation
inline Server::Server()
    : new_task_queue(
          [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); }),
      svr_sock_(INVALID_SOCKET), is_running_(false) {
#ifndef _WIN32
	signal(SIGPIPE, SIG_IGN);
#endif
}

inline Server::~Server() {}

inline Server &Server::Get(const std::string &pattern, Handler handler) {
	get_handlers_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Post(const std::string &pattern, Handler handler) {
	post_handlers_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Post(const std::string &pattern,
                            HandlerWithContentReader handler) {
	post_handlers_for_content_reader_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Put(const std::string &pattern, Handler handler) {
	put_handlers_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Put(const std::string &pattern,
                           HandlerWithContentReader handler) {
	put_handlers_for_content_reader_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Patch(const std::string &pattern, Handler handler) {
	patch_handlers_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Patch(const std::string &pattern,
                             HandlerWithContentReader handler) {
	patch_handlers_for_content_reader_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Delete(const std::string &pattern, Handler handler) {
	delete_handlers_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Delete(const std::string &pattern,
                              HandlerWithContentReader handler) {
	delete_handlers_for_content_reader_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline Server &Server::Options(const std::string &pattern, Handler handler) {
	options_handlers_.push_back(
	    std::make_pair(Regex(pattern), std::move(handler)));
	return *this;
}

inline bool Server::set_base_dir(const std::string &dir,
                                 const std::string &mount_point) {
	return set_mount_point(mount_point, dir);
}

inline bool Server::set_mount_point(const std::string &mount_point,
                                    const std::string &dir, Headers headers) {
	if (detail::is_dir(dir)) {
		std::string mnt = !mount_point.empty() ? mount_point : "/";
		if (!mnt.empty() && mnt[0] == '/') {
			base_dirs_.push_back({mnt, dir, std::move(headers)});
			return true;
		}
	}
	return false;
}

inline bool Server::remove_mount_point(const std::string &mount_point) {
	for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) {
		if (it->mount_point == mount_point) {
			base_dirs_.erase(it);
			return true;
		}
	}
	return false;
}

inline Server &
Server::set_file_extension_and_mimetype_mapping(const char *ext,
                                                const char *mime) {
	file_extension_and_mimetype_map_[ext] = mime;
	return *this;
}

inline Server &Server::set_file_request_handler(Handler handler) {
	file_request_handler_ = std::move(handler);
	return *this;
}

inline Server &Server::set_error_handler(HandlerWithResponse handler) {
	error_handler_ = std::move(handler);
	return *this;
}

inline Server &Server::set_error_handler(Handler handler) {
	error_handler_ = [handler](const Request &req, Response &res) {
		handler(req, res);
		return HandlerResponse::Handled;
	};
	return *this;
}

inline Server &Server::set_exception_handler(ExceptionHandler handler) {
	exception_handler_ = std::move(handler);
	return *this;
}

inline Server &Server::set_pre_routing_handler(HandlerWithResponse handler) {
	pre_routing_handler_ = std::move(handler);
	return *this;
}

inline Server &Server::set_post_routing_handler(Handler handler) {
	post_routing_handler_ = std::move(handler);
	return *this;
}

inline Server &Server::set_logger(Logger logger) {
	logger_ = std::move(logger);
	return *this;
}

inline Server &
Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) {
	expect_100_continue_handler_ = std::move(handler);

	return *this;
}

inline Server &Server::set_address_family(int family) {
	address_family_ = family;
	return *this;
}

inline Server &Server::set_tcp_nodelay(bool on) {
	tcp_nodelay_ = on;
	return *this;
}

inline Server &Server::set_socket_options(SocketOptions socket_options) {
	socket_options_ = std::move(socket_options);
	return *this;
}

inline Server &Server::set_default_headers(Headers headers) {
	default_headers_ = std::move(headers);
	return *this;
}

inline Server &Server::set_keep_alive_max_count(size_t count) {
	keep_alive_max_count_ = count;
	return *this;
}

inline Server &Server::set_keep_alive_timeout(time_t sec) {
	keep_alive_timeout_sec_ = sec;
	return *this;
}

inline Server &Server::set_read_timeout(time_t sec, time_t usec) {
	read_timeout_sec_ = sec;
	read_timeout_usec_ = usec;
	return *this;
}

inline Server &Server::set_write_timeout(time_t sec, time_t usec) {
	write_timeout_sec_ = sec;
	write_timeout_usec_ = usec;
	return *this;
}

inline Server &Server::set_idle_interval(time_t sec, time_t usec) {
	idle_interval_sec_ = sec;
	idle_interval_usec_ = usec;
	return *this;
}

inline Server &Server::set_payload_max_length(size_t length) {
	payload_max_length_ = length;
	return *this;
}

inline bool Server::bind_to_port(const char *host, int port, int socket_flags) {
	if (bind_internal(host, port, socket_flags) < 0) return false;
	return true;
}
inline int Server::bind_to_any_port(const char *host, int socket_flags) {
	return bind_internal(host, 0, socket_flags);
}

inline bool Server::listen_after_bind() { return listen_internal(); }

inline bool Server::listen(const char *host, int port, int socket_flags) {
	return bind_to_port(host, port, socket_flags) && listen_internal();
}

inline bool Server::is_running() const { return is_running_; }

inline void Server::stop() {
	if (is_running_) {
		assert(svr_sock_ != INVALID_SOCKET);
		std::atomic<socket_t> sock(svr_sock_.exchange(INVALID_SOCKET));
		detail::shutdown_socket(sock);
		detail::close_socket(sock);
	}
}

inline bool Server::parse_request_line(const char *s, Request &req) {
	auto len = strlen(s);
	if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; }
	len -= 2;

	{
		size_t count = 0;

		detail::split(s, s + len, ' ', [&](const char *b, const char *e) {
			switch (count) {
			case 0: req.method = std::string(b, e); break;
			case 1: req.target = std::string(b, e); break;
			case 2: req.version = std::string(b, e); break;
			default: break;
			}
			count++;
		});

		if (count != 3) { return false; }
	}

	static const std::set<std::string> methods{
	    "GET",     "HEAD",    "POST",  "PUT",   "DELETE",
	    "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"};

	if (methods.find(req.method) == methods.end()) { return false; }

	if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; }

	{
		size_t count = 0;

		detail::split(req.target.data(), req.target.data() + req.target.size(), '?',
		              [&](const char *b, const char *e) {
			              switch (count) {
			              case 0:
				              req.path = detail::decode_url(std::string(b, e), false);
				              break;
			              case 1: {
				              if (e - b > 0) {
					              detail::parse_query_text(std::string(b, e), req.params);
				              }
				              break;
			              }
			              default: break;
			              }
			              count++;
		              });

		if (count > 2) { return false; }
	}

	return true;
}

inline bool Server::write_response(Stream &strm, bool close_connection,
                                   const Request &req, Response &res) {
	return write_response_core(strm, close_connection, req, res, false);
}

inline bool Server::write_response_with_content(Stream &strm,
                                                bool close_connection,
                                                const Request &req,
                                                Response &res) {
	return write_response_core(strm, close_connection, req, res, true);
}

inline bool Server::write_response_core(Stream &strm, bool close_connection,
                                        const Request &req, Response &res,
                                        bool need_apply_ranges) {
	assert(res.status != -1);

	if (400 <= res.status && error_handler_ &&
	    error_handler_(req, res) == HandlerResponse::Handled) {
		need_apply_ranges = true;
	}

	std::string content_type;
	std::string boundary;
	if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }

	// Prepare additional headers
	if (close_connection || req.get_header_value("Connection") == "close") {
		res.set_header("Connection", "close");
	} else {
		std::stringstream ss;
		ss << "timeout=" << keep_alive_timeout_sec_
		   << ", max=" << keep_alive_max_count_;
		res.set_header("Keep-Alive", ss.str());
	}

	if (!res.has_header("Content-Type") &&
	    (!res.body.empty() || res.content_length_ > 0 || res.content_provider_)) {
		res.set_header("Content-Type", "text/plain");
	}

	if (!res.has_header("Content-Length") && res.body.empty() &&
	    !res.content_length_ && !res.content_provider_) {
		res.set_header("Content-Length", "0");
	}

	if (!res.has_header("Accept-Ranges") && req.method == "HEAD") {
		res.set_header("Accept-Ranges", "bytes");
	}

	if (post_routing_handler_) { post_routing_handler_(req, res); }

	// Response line and headers
	{
		detail::BufferStream bstrm;

		if (!bstrm.write_format("HTTP/1.1 %d %s\r\n", res.status,
		                        detail::status_message(res.status))) {
			return false;
		}

		if (!detail::write_headers(bstrm, res.headers)) { return false; }

		// Flush buffer
		auto &data = bstrm.get_buffer();
		strm.write(data.data(), data.size());
	}

	// Body
	auto ret = true;
	if (req.method != "HEAD") {
		if (!res.body.empty()) {
			if (!strm.write(res.body)) { ret = false; }
		} else if (res.content_provider_) {
			if (write_content_with_provider(strm, req, res, boundary, content_type)) {
				res.content_provider_success_ = true;
			} else {
				res.content_provider_success_ = false;
				ret = false;
			}
		}
	}

	// Log
	if (logger_) { logger_(req, res); }

	return ret;
}

inline bool
Server::write_content_with_provider(Stream &strm, const Request &req,
                                    Response &res, const std::string &boundary,
                                    const std::string &content_type) {
	auto is_shutting_down = [this]() {
		return this->svr_sock_ == INVALID_SOCKET;
	};

	if (res.content_length_ > 0) {
		if (req.ranges.empty()) {
			return detail::write_content(strm, res.content_provider_, 0,
			                             res.content_length_, is_shutting_down);
		} else if (req.ranges.size() == 1) {
			auto offsets =
			    detail::get_range_offset_and_length(req, res.content_length_, 0);
			auto offset = offsets.first;
			auto length = offsets.second;
			return detail::write_content(strm, res.content_provider_, offset, length,
			                             is_shutting_down);
		} else {
			return detail::write_multipart_ranges_data(
			    strm, req, res, boundary, content_type, is_shutting_down);
		}
	} else {
		if (res.is_chunked_content_provider_) {
			auto type = detail::encoding_type(req, res);

			std::unique_ptr<detail::compressor> compressor;
			if (type == detail::EncodingType::Gzip) {
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
				compressor = detail::make_unique<detail::gzip_compressor>();
#endif
			} else if (type == detail::EncodingType::Brotli) {
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
				compressor = detail::make_unique<detail::brotli_compressor>();
#endif
			} else {
				compressor = detail::make_unique<detail::nocompressor>();
			}
			assert(compressor != nullptr);

			return detail::write_content_chunked(strm, res.content_provider_,
			                                     is_shutting_down, *compressor);
		} else {
			return detail::write_content_without_length(strm, res.content_provider_,
			                                            is_shutting_down);
		}
	}
}

inline bool Server::read_content(Stream &strm, Request &req, Response &res) {
	MultipartFormDataMap::iterator cur;
	if (read_content_core(
	        strm, req, res,
	        // Regular
	        [&](const char *buf, size_t n) {
		        if (req.body.size() + n > req.body.max_size()) { return false; }
		        req.body.append(buf, n);
		        return true;
	        },
	        // Multipart
	        [&](const MultipartFormData &file) {
		        cur = req.files.emplace(file.name, file);
		        return true;
	        },
	        [&](const char *buf, size_t n) {
		        auto &content = cur->second.content;
		        if (content.size() + n > content.max_size()) { return false; }
		        content.append(buf, n);
		        return true;
	        })) {
		const auto &content_type = req.get_header_value("Content-Type");
		if (!content_type.find("application/x-www-form-urlencoded")) {
			if (req.body.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
				res.status = 413; // NOTE: should be 414?
				return false;
			}
			detail::parse_query_text(req.body, req.params);
		}
		return true;
	}
	return false;
}

inline bool Server::read_content_with_content_receiver(
    Stream &strm, Request &req, Response &res, ContentReceiver receiver,
    MultipartContentHeader multipart_header,
    ContentReceiver multipart_receiver) {
	return read_content_core(strm, req, res, std::move(receiver),
	                         std::move(multipart_header),
	                         std::move(multipart_receiver));
}

inline bool Server::read_content_core(Stream &strm, Request &req, Response &res,
                                      ContentReceiver receiver,
                                      MultipartContentHeader mulitpart_header,
                                      ContentReceiver multipart_receiver) {
	detail::MultipartFormDataParser multipart_form_data_parser;
	ContentReceiverWithProgress out;

	if (req.is_multipart_form_data()) {
		const auto &content_type = req.get_header_value("Content-Type");
		std::string boundary;
		if (!detail::parse_multipart_boundary(content_type, boundary)) {
			res.status = 400;
			return false;
		}

		multipart_form_data_parser.set_boundary(std::move(boundary));
		out = [&](const char *buf, size_t n, uint64_t /*off*/, uint64_t /*len*/) {
			/* For debug
			size_t pos = 0;
			while (pos < n) {
			  auto read_size = (std::min)<size_t>(1, n - pos);
			  auto ret = multipart_form_data_parser.parse(
			      buf + pos, read_size, multipart_receiver, mulitpart_header);
			  if (!ret) { return false; }
			  pos += read_size;
			}
			return true;
			*/
			return multipart_form_data_parser.parse(buf, n, multipart_receiver,
			                                        mulitpart_header);
		};
	} else {
		out = [receiver](const char *buf, size_t n, uint64_t /*off*/,
		                 uint64_t /*len*/) { return receiver(buf, n); };
	}

	if (req.method == "DELETE" && !req.has_header("Content-Length")) {
		return true;
	}

	if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr,
	                          out, true)) {
		return false;
	}

	if (req.is_multipart_form_data()) {
		if (!multipart_form_data_parser.is_valid()) {
			res.status = 400;
			return false;
		}
	}

	return true;
}

inline bool Server::handle_file_request(const Request &req, Response &res,
                                        bool head) {
	for (const auto &entry : base_dirs_) {
		// Prefix match
		if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) {
			std::string sub_path = "/" + req.path.substr(entry.mount_point.size());
			if (detail::is_valid_path(sub_path)) {
				auto path = entry.base_dir + sub_path;
				if (path.back() == '/') { path += "index.html"; }

				if (detail::is_file(path)) {
					detail::read_file(path, res.body);
					auto type =
					    detail::find_content_type(path, file_extension_and_mimetype_map_);
					if (type) { res.set_header("Content-Type", type); }
					for (const auto &kv : entry.headers) {
						res.set_header(kv.first.c_str(), kv.second);
					}
					res.status = req.has_header("Range") ? 206 : 200;
					if (!head && file_request_handler_) {
						file_request_handler_(req, res);
					}
					return true;
				}
			}
		}
	}
	return false;
}

inline socket_t
Server::create_server_socket(const char *host, int port, int socket_flags,
                             SocketOptions socket_options) const {
	return detail::create_socket(
	    host, "", port, address_family_, socket_flags, tcp_nodelay_,
	    std::move(socket_options),
	    [](socket_t sock, struct addrinfo &ai) -> bool {
		    if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
			    return false;
		    }
		    if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; }
		    return true;
	    });
}

inline int Server::bind_internal(const char *host, int port, int socket_flags) {
	if (!is_valid()) { return -1; }

	svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
	if (svr_sock_ == INVALID_SOCKET) { return -1; }

	if (port == 0) {
		struct sockaddr_storage addr;
		socklen_t addr_len = sizeof(addr);
		if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&addr),
		                &addr_len) == -1) {
			return -1;
		}
		if (addr.ss_family == AF_INET) {
			return ntohs(reinterpret_cast<struct sockaddr_in *>(&addr)->sin_port);
		} else if (addr.ss_family == AF_INET6) {
			return ntohs(reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_port);
		} else {
			return -1;
		}
	} else {
		return port;
	}
}

inline bool Server::listen_internal() {
	auto ret = true;
	is_running_ = true;

	{
		std::unique_ptr<TaskQueue> task_queue(new_task_queue());

		while (svr_sock_ != INVALID_SOCKET) {
#ifndef _WIN32
			if (idle_interval_sec_ > 0 || idle_interval_usec_ > 0) {
#endif
				auto val = detail::select_read(svr_sock_, idle_interval_sec_,
				                               idle_interval_usec_);
				if (val == 0) { // Timeout
					task_queue->on_idle();
					continue;
				}
#ifndef _WIN32
			}
#endif
			socket_t sock = accept(svr_sock_, nullptr, nullptr);

			if (sock == INVALID_SOCKET) {
				if (errno == EMFILE) {
					// The per-process limit of open file descriptors has been reached.
					// Try to accept new connections after a short sleep.
					std::this_thread::sleep_for(std::chrono::milliseconds(1));
					continue;
				}
				if (svr_sock_ != INVALID_SOCKET) {
					detail::close_socket(svr_sock_);
					ret = false;
				} else {
					; // The server socket was closed by user.
				}
				break;
			}

			{
#ifdef _WIN32
				auto timeout = static_cast<uint32_t>(read_timeout_sec_ * 1000 +
				                                     read_timeout_usec_ / 1000);
				setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
				           sizeof(timeout));
#else
				timeval tv;
				tv.tv_sec = static_cast<long>(read_timeout_sec_);
				tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec_);
				setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
#endif
			}
			{

#ifdef _WIN32
				auto timeout = static_cast<uint32_t>(write_timeout_sec_ * 1000 +
				                                     write_timeout_usec_ / 1000);
				setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
				           sizeof(timeout));
#else
				timeval tv;
				tv.tv_sec = static_cast<long>(write_timeout_sec_);
				tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec_);
				setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
#endif
			}

#if __cplusplus > 201703L
			task_queue->enqueue([=, this]() { process_and_close_socket(sock); });
#else
			task_queue->enqueue([=]() { process_and_close_socket(sock); });
#endif
		}

		task_queue->shutdown();
	}

	is_running_ = false;
	return ret;
}

inline bool Server::routing(Request &req, Response &res, Stream &strm) {
	if (pre_routing_handler_ &&
	    pre_routing_handler_(req, res) == HandlerResponse::Handled) {
		return true;
	}

	// File handler
	bool is_head_request = req.method == "HEAD";
	if ((req.method == "GET" || is_head_request) &&
	    handle_file_request(req, res, is_head_request)) {
		return true;
	}

	if (detail::expect_content(req)) {
		// Content reader handler
		{
			ContentReader reader(
			    [&](ContentReceiver receiver) {
				    return read_content_with_content_receiver(
				        strm, req, res, std::move(receiver), nullptr, nullptr);
			    },
			    [&](MultipartContentHeader header, ContentReceiver receiver) {
				    return read_content_with_content_receiver(strm, req, res, nullptr,
				                                              std::move(header),
				                                              std::move(receiver));
			    });

			if (req.method == "POST") {
				if (dispatch_request_for_content_reader(
				        req, res, std::move(reader),
				        post_handlers_for_content_reader_)) {
					return true;
				}
			} else if (req.method == "PUT") {
				if (dispatch_request_for_content_reader(
				        req, res, std::move(reader),
				        put_handlers_for_content_reader_)) {
					return true;
				}
			} else if (req.method == "PATCH") {
				if (dispatch_request_for_content_reader(
				        req, res, std::move(reader),
				        patch_handlers_for_content_reader_)) {
					return true;
				}
			} else if (req.method == "DELETE") {
				if (dispatch_request_for_content_reader(
				        req, res, std::move(reader),
				        delete_handlers_for_content_reader_)) {
					return true;
				}
			}
		}

		// Read content into `req.body`
		if (!read_content(strm, req, res)) { return false; }
	}

	// Regular handler
	if (req.method == "GET" || req.method == "HEAD") {
		return dispatch_request(req, res, get_handlers_);
	} else if (req.method == "POST") {
		return dispatch_request(req, res, post_handlers_);
	} else if (req.method == "PUT") {
		return dispatch_request(req, res, put_handlers_);
	} else if (req.method == "DELETE") {
		return dispatch_request(req, res, delete_handlers_);
	} else if (req.method == "OPTIONS") {
		return dispatch_request(req, res, options_handlers_);
	} else if (req.method == "PATCH") {
		return dispatch_request(req, res, patch_handlers_);
	}

	res.status = 400;
	return false;
}

inline bool Server::dispatch_request(Request &req, Response &res,
                                     const Handlers &handlers) {
	for (const auto &x : handlers) {
		const auto &pattern = x.first;
		const auto &handler = x.second;

		if (duckdb_re2::RegexMatch(req.path, req.matches, pattern)) {
			handler(req, res);
			return true;
		}
	}
	return false;
}

inline void Server::apply_ranges(const Request &req, Response &res,
                                 std::string &content_type,
                                 std::string &boundary) {
	if (req.ranges.size() > 1) {
		boundary = detail::make_multipart_data_boundary();

		auto it = res.headers.find("Content-Type");
		if (it != res.headers.end()) {
			content_type = it->second;
			res.headers.erase(it);
		}

		res.headers.emplace("Content-Type",
		                    "multipart/byteranges; boundary=" + boundary);
	}

	auto type = detail::encoding_type(req, res);

	if (res.body.empty()) {
		if (res.content_length_ > 0) {
			size_t length = 0;
			if (req.ranges.empty()) {
				length = res.content_length_;
			} else if (req.ranges.size() == 1) {
				auto offsets =
				    detail::get_range_offset_and_length(req, res.content_length_, 0);
				auto offset = offsets.first;
				length = offsets.second;
				auto content_range = detail::make_content_range_header_field(
				    offset, length, res.content_length_);
				res.set_header("Content-Range", content_range);
			} else {
				length = detail::get_multipart_ranges_data_length(req, res, boundary,
				                                                  content_type);
			}
			res.set_header("Content-Length", std::to_string(length));
		} else {
			if (res.content_provider_) {
				if (res.is_chunked_content_provider_) {
					res.set_header("Transfer-Encoding", "chunked");
					if (type == detail::EncodingType::Gzip) {
						res.set_header("Content-Encoding", "gzip");
					} else if (type == detail::EncodingType::Brotli) {
						res.set_header("Content-Encoding", "br");
					}
				}
			}
		}
	} else {
		if (req.ranges.empty()) {
			;
		} else if (req.ranges.size() == 1) {
			auto offsets =
			    detail::get_range_offset_and_length(req, res.body.size(), 0);
			auto offset = offsets.first;
			auto length = offsets.second;
			auto content_range = detail::make_content_range_header_field(
			    offset, length, res.body.size());
			res.set_header("Content-Range", content_range);
			if (offset < res.body.size()) {
				res.body = res.body.substr(offset, length);
			} else {
				res.body.clear();
				res.status = 416;
			}
		} else {
			std::string data;
			if (detail::make_multipart_ranges_data(req, res, boundary, content_type,
			                                       data)) {
				res.body.swap(data);
			} else {
				res.body.clear();
				res.status = 416;
			}
		}

		if (type != detail::EncodingType::None) {
			std::unique_ptr<detail::compressor> compressor;
			std::string content_encoding;

			if (type == detail::EncodingType::Gzip) {
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
				compressor = detail::make_unique<detail::gzip_compressor>();
				content_encoding = "gzip";
#endif
			} else if (type == detail::EncodingType::Brotli) {
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
				compressor = detail::make_unique<detail::brotli_compressor>();
				content_encoding = "br";
#endif
			}

			if (compressor) {
				std::string compressed;
				if (compressor->compress(res.body.data(), res.body.size(), true,
				                         [&](const char *data, size_t data_len) {
					                         compressed.append(data, data_len);
					                         return true;
				                         })) {
					res.body.swap(compressed);
					res.set_header("Content-Encoding", content_encoding);
				}
			}
		}

		auto length = std::to_string(res.body.size());
		res.set_header("Content-Length", length);
	}
}

inline bool Server::dispatch_request_for_content_reader(
    Request &req, Response &res, ContentReader content_reader,
    const HandlersForContentReader &handlers) {
	for (const auto &x : handlers) {
		const auto &pattern = x.first;
		const auto &handler = x.second;

		if (duckdb_re2::RegexMatch(req.path, req.matches, pattern)) {
			handler(req, res, content_reader);
			return true;
		}
	}
	return false;
}

inline bool
Server::process_request(Stream &strm, bool close_connection,
                        bool &connection_closed,
                        const std::function<void(Request &)> &setup_request) {
	std::array<char, 2048> buf{};

	detail::stream_line_reader line_reader(strm, buf.data(), buf.size());

	// Connection has been closed on client
	if (!line_reader.getline()) { return false; }

	Request req;
	Response res;

	res.version = "HTTP/1.1";

	for (const auto &header : default_headers_) {
		if (res.headers.find(header.first) == res.headers.end()) {
			res.headers.insert(header);
		}
	}

#ifdef _WIN32
	// TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL).
#else
#ifndef CPPHTTPLIB_USE_POLL
	// Socket file descriptor exceeded FD_SETSIZE...
	if (strm.socket() >= FD_SETSIZE) {
		Headers dummy;
		detail::read_headers(strm, dummy);
		res.status = 500;
		return write_response(strm, close_connection, req, res);
	}
#endif
#endif

	// Check if the request URI doesn't exceed the limit
	if (line_reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
		Headers dummy;
		detail::read_headers(strm, dummy);
		res.status = 414;
		return write_response(strm, close_connection, req, res);
	}

	// Request line and headers
	if (!parse_request_line(line_reader.ptr(), req) ||
	    !detail::read_headers(strm, req.headers)) {
		res.status = 400;
		return write_response(strm, close_connection, req, res);
	}

	if (req.get_header_value("Connection") == "close") {
		connection_closed = true;
	}

	if (req.version == "HTTP/1.0" &&
	    req.get_header_value("Connection") != "Keep-Alive") {
		connection_closed = true;
	}

	strm.get_remote_ip_and_port(req.remote_addr, req.remote_port);
	req.set_header("REMOTE_ADDR", req.remote_addr);
	req.set_header("REMOTE_PORT", std::to_string(req.remote_port));

	if (req.has_header("Range")) {
		const auto &range_header_value = req.get_header_value("Range");
		if (!detail::parse_range_header(range_header_value, req.ranges)) {
			res.status = 416;
			return write_response(strm, close_connection, req, res);
		}
	}

	if (setup_request) { setup_request(req); }

	if (req.get_header_value("Expect") == "100-continue") {
		auto status = 100;
		if (expect_100_continue_handler_) {
			status = expect_100_continue_handler_(req, res);
		}
		switch (status) {
		case 100:
		case 417:
			strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status,
			                  detail::status_message(status));
			break;
		default: return write_response(strm, close_connection, req, res);
		}
	}

	// Rounting
	bool routed = false;
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
	routed = routing(req, res, strm);
#else
	try {
		routed = routing(req, res, strm);
	} catch (std::exception &e) {
		if (exception_handler_) {
			exception_handler_(req, res, e);
			routed = true;
		} else {
			res.status = 500;
			res.set_header("EXCEPTION_WHAT", e.what());
		}
	} catch (...) {
		res.status = 500;
		res.set_header("EXCEPTION_WHAT", "UNKNOWN");
	}
#endif

	if (routed) {
		if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; }
		return write_response_with_content(strm, close_connection, req, res);
	} else {
		if (res.status == -1) { res.status = 404; }
		return write_response(strm, close_connection, req, res);
	}
}

inline bool Server::is_valid() const { return true; }

inline bool Server::process_and_close_socket(socket_t sock) {
	auto ret = detail::process_server_socket(
	    svr_sock_, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
	    read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
	    write_timeout_usec_,
	    [this](Stream &strm, bool close_connection, bool &connection_closed) {
		    return process_request(strm, close_connection, connection_closed,
		                           nullptr);
	    });

	detail::shutdown_socket(sock);
	detail::close_socket(sock);
	return ret;
}

// HTTP client implementation
inline ClientImpl::ClientImpl(const std::string &host)
    : ClientImpl(host, 80, std::string(), std::string()) {}

inline ClientImpl::ClientImpl(const std::string &host, int port)
    : ClientImpl(host, port, std::string(), std::string()) {}

inline ClientImpl::ClientImpl(const std::string &host, int port,
                              const std::string &client_cert_path,
                              const std::string &client_key_path)
    : host_(host), port_(port),
      host_and_port_(adjust_host_string(host) + ":" + std::to_string(port)),
      client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}

inline ClientImpl::~ClientImpl() {
	std::lock_guard<std::mutex> guard(socket_mutex_);
	shutdown_socket(socket_);
	close_socket(socket_);
}

inline bool ClientImpl::is_valid() const { return true; }

inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
	client_cert_path_ = rhs.client_cert_path_;
	client_key_path_ = rhs.client_key_path_;
	connection_timeout_sec_ = rhs.connection_timeout_sec_;
	read_timeout_sec_ = rhs.read_timeout_sec_;
	read_timeout_usec_ = rhs.read_timeout_usec_;
	write_timeout_sec_ = rhs.write_timeout_sec_;
	write_timeout_usec_ = rhs.write_timeout_usec_;
	basic_auth_username_ = rhs.basic_auth_username_;
	basic_auth_password_ = rhs.basic_auth_password_;
	bearer_token_auth_token_ = rhs.bearer_token_auth_token_;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	digest_auth_username_ = rhs.digest_auth_username_;
	digest_auth_password_ = rhs.digest_auth_password_;
#endif
	keep_alive_ = rhs.keep_alive_;
	follow_location_ = rhs.follow_location_;
	url_encode_ = rhs.url_encode_;
	address_family_ = rhs.address_family_;
	tcp_nodelay_ = rhs.tcp_nodelay_;
	socket_options_ = rhs.socket_options_;
	compress_ = rhs.compress_;
	decompress_ = rhs.decompress_;
	interface_ = rhs.interface_;
	proxy_host_ = rhs.proxy_host_;
	proxy_port_ = rhs.proxy_port_;
	proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_;
	proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_;
	proxy_bearer_token_auth_token_ = rhs.proxy_bearer_token_auth_token_;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
	proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	ca_cert_file_path_ = rhs.ca_cert_file_path_;
	ca_cert_dir_path_ = rhs.ca_cert_dir_path_;
	ca_cert_store_ = rhs.ca_cert_store_;
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	server_certificate_verification_ = rhs.server_certificate_verification_;
#endif
	logger_ = rhs.logger_;
}

inline socket_t ClientImpl::create_client_socket(Error &error) const {
	if (!proxy_host_.empty() && proxy_port_ != -1) {
		return detail::create_client_socket(
		    proxy_host_.c_str(), "", proxy_port_, address_family_, tcp_nodelay_,
		    socket_options_, connection_timeout_sec_, connection_timeout_usec_,
		    read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
		    write_timeout_usec_, interface_, error);
	}

	// Check is custom IP specified for host_
	std::string ip;
	auto it = addr_map_.find(host_);
	if (it != addr_map_.end()) ip = it->second;

	return detail::create_client_socket(
	    host_.c_str(), ip.c_str(), port_, address_family_, tcp_nodelay_,
	    socket_options_, connection_timeout_sec_, connection_timeout_usec_,
	    read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
	    write_timeout_usec_, interface_, error);
}

inline bool ClientImpl::create_and_connect_socket(Socket &socket,
                                                  Error &error) {
	auto sock = create_client_socket(error);
	if (sock == INVALID_SOCKET) { return false; }
	socket.sock = sock;
	return true;
}

inline void ClientImpl::shutdown_ssl(Socket & /*socket*/,
                                     bool /*shutdown_gracefully*/) {
	// If there are any requests in flight from threads other than us, then it's
	// a thread-unsafe race because individual ssl* objects are not thread-safe.
	assert(socket_requests_in_flight_ == 0 ||
	       socket_requests_are_from_thread_ == std::this_thread::get_id());
}

inline void ClientImpl::shutdown_socket(Socket &socket) {
	if (socket.sock == INVALID_SOCKET) { return; }
	detail::shutdown_socket(socket.sock);
}

inline void ClientImpl::close_socket(Socket &socket) {
	// If there are requests in flight in another thread, usually closing
	// the socket will be fine and they will simply receive an error when
	// using the closed socket, but it is still a bug since rarely the OS
	// may reassign the socket id to be used for a new socket, and then
	// suddenly they will be operating on a live socket that is different
	// than the one they intended!
	assert(socket_requests_in_flight_ == 0 ||
	       socket_requests_are_from_thread_ == std::this_thread::get_id());

	// It is also a bug if this happens while SSL is still active
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	assert(socket.ssl == nullptr);
#endif
	if (socket.sock == INVALID_SOCKET) { return; }
	detail::close_socket(socket.sock);
	socket.sock = INVALID_SOCKET;
}

inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
                                           Response &res) {
	std::array<char, 2048> buf{};

	detail::stream_line_reader line_reader(strm, buf.data(), buf.size());

	if (!line_reader.getline()) { return false; }

#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
	const static Regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
#else
	const static Regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
#endif

	Match m;
	if (!duckdb_re2::RegexMatch(line_reader.ptr(), m, re)) {
		return req.method == "CONNECT";
	}
	res.version = std::string(m[1]);
	res.status = std::stoi(std::string(m[2]));
	res.reason = std::string(m[3]);

	// Ignore '100 Continue'
	while (res.status == 100) {
		if (!line_reader.getline()) { return false; } // CRLF
		if (!line_reader.getline()) { return false; } // next response line

		if (!duckdb_re2::RegexMatch(line_reader.ptr(), m, re)) { return false; }
		res.version = std::string(m[1]);
		res.status = std::stoi(std::string(m[2]));
		res.reason = std::string(m[3]);
	}

	return true;
}

inline bool ClientImpl::send(Request &req, Response &res, Error &error) {
	std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);

	{
		std::lock_guard<std::mutex> guard(socket_mutex_);

		// Set this to false immediately - if it ever gets set to true by the end of
		// the request, we know another thread instructed us to close the socket.
		socket_should_be_closed_when_request_is_done_ = false;

		auto is_alive = false;
		if (socket_.is_open()) {
			is_alive = detail::is_socket_alive(socket_.sock);
			if (!is_alive) {
				// Attempt to avoid sigpipe by shutting down nongracefully if it seems
				// like the other side has already closed the connection Also, there
				// cannot be any requests in flight from other threads since we locked
				// request_mutex_, so safe to close everything immediately
				const bool shutdown_gracefully = false;
				shutdown_ssl(socket_, shutdown_gracefully);
				shutdown_socket(socket_);
				close_socket(socket_);
			}
		}

		if (!is_alive) {
			if (!create_and_connect_socket(socket_, error)) { return false; }

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
			// TODO: refactoring
			if (is_ssl()) {
				auto &scli = static_cast<SSLClient &>(*this);
				if (!proxy_host_.empty() && proxy_port_ != -1) {
					bool success = false;
					if (!scli.connect_with_proxy(socket_, res, success, error)) {
						return success;
					}
				}

				if (!scli.initialize_ssl(socket_, error)) { return false; }
			}
#endif
		}

		// Mark the current socket as being in use so that it cannot be closed by
		// anyone else while this request is ongoing, even though we will be
		// releasing the mutex.
		if (socket_requests_in_flight_ > 1) {
			assert(socket_requests_are_from_thread_ == std::this_thread::get_id());
		}
		socket_requests_in_flight_ += 1;
		socket_requests_are_from_thread_ = std::this_thread::get_id();
	}

	for (const auto &header : default_headers_) {
		if (req.headers.find(header.first) == req.headers.end()) {
			req.headers.insert(header);
		}
	}

	auto close_connection = !keep_alive_;
	auto ret = process_socket(socket_, [&](Stream &strm) {
		return handle_request(strm, req, res, close_connection, error);
	});

	// Briefly lock mutex in order to mark that a request is no longer ongoing
	{
		std::lock_guard<std::mutex> guard(socket_mutex_);
		socket_requests_in_flight_ -= 1;
		if (socket_requests_in_flight_ <= 0) {
			assert(socket_requests_in_flight_ == 0);
			socket_requests_are_from_thread_ = std::thread::id();
		}

		if (socket_should_be_closed_when_request_is_done_ || close_connection ||
		    !ret) {
			shutdown_ssl(socket_, true);
			shutdown_socket(socket_);
			close_socket(socket_);
		}
	}

	if (!ret) {
		if (error == Error::Success) { error = Error::Unknown; }
	}

	return ret;
}

inline Result ClientImpl::send(const Request &req) {
	auto req2 = req;
	return send_(std::move(req2));
}

inline Result ClientImpl::send_(Request &&req) {
	auto res = detail::make_unique<Response>();
	auto error = Error::Success;
	auto ret = send(req, *res, error);
	return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)};
}

inline bool ClientImpl::handle_request(Stream &strm, Request &req,
                                       Response &res, bool close_connection,
                                       Error &error) {
	if (req.path.empty()) {
		error = Error::Connection;
		return false;
	}

	auto req_save = req;

	bool ret;

	if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) {
		auto req2 = req;
		req2.path = "http://" + host_and_port_ + req.path;
		ret = process_request(strm, req2, res, close_connection, error);
		req = req2;
		req.path = req_save.path;
	} else {
		ret = process_request(strm, req, res, close_connection, error);
	}

	if (!ret) { return false; }

	if (300 < res.status && res.status < 400 && follow_location_) {
		req = req_save;
		ret = redirect(req, res, error);
	}

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
	if ((res.status == 401 || res.status == 407) &&
	    req.authorization_count_ < 5) {
		auto is_proxy = res.status == 407;
		const auto &username =
		    is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
		const auto &password =
		    is_proxy ? proxy_digest_auth_password_ : digest_auth_password_;

		if (!username.empty() && !password.empty()) {
			std::map<std::string, std::string> auth;
			if (detail::parse_www_authenticate(res, auth, is_proxy)) {
				Request new_req = req;
				new_req.authorization_count_ += 1;
				new_req.headers.erase(is_proxy ? "Proxy-Authorization"
				                               : "Authorization");
				new_req.headers.insert(detail::make_digest_authentication_header(
				    req, auth, new_req.authorization_count_, detail::random_string(10),
				    username, password, is_proxy));

				Response new_res;

				ret = send(new_req, new_res, error);
				if (ret) { res = new_res; }
			}
		}
	}
#endif

	return ret;
}

inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
	if (req.redirect_count_ == 0) {
		error = Error::ExceedRedirectCount;
		return false;
	}

	auto location = detail::decode_url(res.get_header_value("location"), false);
	if (location.empty()) { return false; }

	const static Regex re(
	    R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");

	Match m;
	if (!duckdb_re2::RegexMatch(location, m, re)) { return false; }

	auto scheme = is_ssl() ? "https" : "http";

	auto next_scheme = m[1].str();
	auto next_host = m[2].str();
	if (next_host.empty()) { next_host = m[3].str(); }
	auto port_str = m[4].str();
	auto next_path = m[5].str();

	auto next_port = port_;
	if (!port_str.empty()) {
		next_port = std::stoi(port_str);
	} else if (!next_scheme.empty()) {
		next_port = next_scheme == "https" ? 443 : 80;
	}

	if (next_scheme.empty()) { next_scheme = scheme; }
	if (next_host.empty()) { next_host = host_; }
	if (next_path.empty()) { next_path = "/"; }

	if (next_scheme == scheme && next_host == host_ && next_port == port_) {
		return detail::redirect(*this, req, res, next_path, location, error);
	} else {
		if (next_scheme == "https") {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
			SSLClient cli(next_host.c_str(), next_port);
			cli.copy_settings(*this);
			if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); }
			return detail::redirect(cli, req, res, next_path, location, error);
#else
			return false;
#endif
		} else {
			ClientImpl cli(next_host.c_str(), next_port);
			cli.copy_settings(*this);
			return detail::redirect(cli, req, res, next_path, location, error);
		}
	}
}

inline bool ClientImpl::write_content_with_provider(Stream &strm,
                                                    const Request &req,
                                                    Error &error) {
	auto is_shutting_down = []() { return false; };

	if (req.is_chunked_content_provider_) {
		// TODO: Brotli suport
		std::unique_ptr<detail::compressor> compressor;
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
		if (compress_) {
			compressor = detail::make_unique<detail::gzip_compressor>();
		} else
#endif
		{
			compressor = detail::make_unique<detail::nocompressor>();
		}

		return detail::write_content_chunked(strm, req.content_provider_,
		                                     is_shutting_down, *compressor, error);
	} else {
		return detail::write_content(strm, req.content_provider_, 0,
		                             req.content_length_, is_shutting_down, error);
	}
} // namespace CPPHTTPLIB_NAMESPACE

inline bool ClientImpl::write_request(Stream &strm, Request &req,
                                      bool close_connection, Error &error) {
	// Prepare additional headers
	if (close_connection) {
		if (!req.has_header("Connection")) {
			req.headers.emplace("Connection", "close");
		}
	}

	if (!req.has_header("Host")) {
		if (is_ssl()) {
			if (port_ == 443) {
				req.headers.emplace("Host", host_);
			} else {
				req.headers.emplace("Host", host_and_port_);
			}
		} else {
			if (port_ == 80) {
				req.headers.emplace("Host", host_);
			} else {
				req.headers.emplace("Host", host_and_port_);
			}
		}
	}

	if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); }

	if (!req.has_header("User-Agent")) {
		req.headers.emplace("User-Agent", "cpp-httplib/0.10.1");
	}

	if (req.body.empty()) {
		if (req.content_provider_) {
			if (!req.is_chunked_content_provider_) {
				if (!req.has_header("Content-Length")) {
					auto length = std::to_string(req.content_length_);
					req.headers.emplace("Content-Length", length);
				}
			}
		} else {
			if (req.method == "POST" || req.method == "PUT" ||
			    req.method == "PATCH") {
				req.headers.emplace("Content-Length", "0");
			}
		}
	} else {
		if (!req.has_header("Content-Type")) {
			req.headers.emplace("Content-Type", "text/plain");
		}

		if (!req.has_header("Content-Length")) {
			auto length = std::to_string(req.body.size());
			req.headers.emplace("Content-Length", length);
		}
	}

	if (!basic_auth_password_.empty() || !basic_auth_username_.empty()) {
		if (!req.has_header("Authorization")) {
			req.headers.insert(make_basic_authentication_header(
			    basic_auth_username_, basic_auth_password_, false));
		}
	}

	if (!proxy_basic_auth_username_.empty() &&
	    !proxy_basic_auth_password_.empty()) {
		if (!req.has_header("Proxy-Authorization")) {
			req.headers.insert(make_basic_authentication_header(
			    proxy_basic_auth_username_, proxy_basic_auth_password_, true));
		}
	}

	if (!bearer_token_auth_token_.empty()) {
		if (!req.has_header("Authorization")) {
			req.headers.insert(make_bearer_token_authentication_header(
			    bearer_token_auth_token_, false));
		}
	}

	if (!proxy_bearer_token_auth_token_.empty()) {
		if (!req.has_header("Proxy-Authorization")) {
			req.headers.insert(make_bearer_token_authentication_header(
			    proxy_bearer_token_auth_token_, true));
		}
	}

	// Request line and headers
	{
		detail::BufferStream bstrm;

		const auto &path = url_encode_ ? detail::encode_url(req.path) : req.path;
		bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());

		detail::write_headers(bstrm, req.headers);

		// Flush buffer
		auto &data = bstrm.get_buffer();
		if (!detail::write_data(strm, data.data(), data.size())) {
			error = Error::Write;
			return false;
		}
	}

	// Body
	if (req.body.empty()) {
		return write_content_with_provider(strm, req, error);
	}

	if (!detail::write_data(strm, req.body.data(), req.body.size())) {
		error = Error::Write;
		return false;
	}

	return true;
}

inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
    Request &req,
    // const char *method, const char *path, const Headers &headers,
    const char *body, size_t content_length, ContentProvider content_provider,
    ContentProviderWithoutLength content_provider_without_length,
    const char *content_type, Error &error) {

	if (content_type) { req.headers.emplace("Content-Type", content_type); }

#ifdef CPPHTTPLIB_ZLIB_SUPPORT
	if (compress_) { req.headers.emplace("Content-Encoding", "gzip"); }
#endif

#ifdef CPPHTTPLIB_ZLIB_SUPPORT
	if (compress_ && !content_provider_without_length) {
		// TODO: Brotli support
		detail::gzip_compressor compressor;

		if (content_provider) {
			auto ok = true;
			size_t offset = 0;
			DataSink data_sink;

			data_sink.write = [&](const char *data, size_t data_len) -> bool {
				if (ok) {
					auto last = offset + data_len == content_length;

					auto ret = compressor.compress(
					    data, data_len, last, [&](const char *data, size_t data_len) {
						    req.body.append(data, data_len);
						    return true;
					    });

					if (ret) {
						offset += data_len;
					} else {
						ok = false;
					}
				}
				return ok;
			};

			data_sink.is_writable = [&](void) { return ok && true; };

			while (ok && offset < content_length) {
				if (!content_provider(offset, content_length - offset, data_sink)) {
					error = Error::Canceled;
					return nullptr;
				}
			}
		} else {
			if (!compressor.compress(body, content_length, true,
			                         [&](const char *data, size_t data_len) {
				                         req.body.append(data, data_len);
				                         return true;
			                         })) {
				error = Error::Compression;
				return nullptr;
			}
		}
	} else
#endif
	{
		if (content_provider) {
			req.content_length_ = content_length;
			req.content_provider_ = std::move(content_provider);
			req.is_chunked_content_provider_ = false;
		} else if (content_provider_without_length) {
			req.content_length_ = 0;
			req.content_provider_ = detail::ContentProviderAdapter(
			    std::move(content_provider_without_length));
			req.is_chunked_content_provider_ = true;
			req.headers.emplace("Transfer-Encoding", "chunked");
		} else {
			req.body.assign(body, content_length);
			;
		}
	}

	auto res = detail::make_unique<Response>();
	return send(req, *res, error) ? std::move(res) : nullptr;
}

inline Result ClientImpl::send_with_content_provider(
    const char *method, const char *path, const Headers &headers,
    const char *body, size_t content_length, ContentProvider content_provider,
    ContentProviderWithoutLength content_provider_without_length,
    const char *content_type) {
	Request req;
	req.method = method;
	req.headers = headers;
	req.path = path;

	auto error = Error::Success;

	auto res = send_with_content_provider(
	    req,
	    // method, path, headers,
	    body, content_length, std::move(content_provider),
	    std::move(content_provider_without_length), content_type, error);

	return Result{std::move(res), error, std::move(req.headers)};
}

inline std::string
ClientImpl::adjust_host_string(const std::string &host) const {
	if (host.find(':') != std::string::npos) { return "[" + host + "]"; }
	return host;
}

inline bool ClientImpl::process_request(Stream &strm, Request &req,
                                        Response &res, bool close_connection,
                                        Error &error) {
	// Send request
	if (!write_request(strm, req, close_connection, error)) { return false; }

	// Receive response and headers
	if (!read_response_line(strm, req, res) ||
	    !detail::read_headers(strm, res.headers)) {
		error = Error::Read;
		return false;
	}

	// Body
	if ((res.status != 204) && req.method != "HEAD" && req.method != "CONNECT") {
		auto redirect = 300 < res.status && res.status < 400 && follow_location_;

		if (req.response_handler && !redirect) {
			if (!req.response_handler(res)) {
				error = Error::Canceled;
				return false;
			}
		}

		auto out =
		    req.content_receiver
		        ? static_cast<ContentReceiverWithProgress>(
		              [&](const char *buf, size_t n, uint64_t off, uint64_t len) {
			              if (redirect) { return true; }
			              auto ret = req.content_receiver(buf, n, off, len);
			              if (!ret) { error = Error::Canceled; }
			              return ret;
		              })
		        : static_cast<ContentReceiverWithProgress>(
		              [&](const char *buf, size_t n, uint64_t /*off*/,
		                  uint64_t /*len*/) {
			              if (res.body.size() + n > res.body.max_size()) {
				              return false;
			              }
			              res.body.append(buf, n);
			              return true;
		              });

		auto progress = [&](uint64_t current, uint64_t total) {
			if (!req.progress || redirect) { return true; }
			auto ret = req.progress(current, total);
			if (!ret) { error = Error::Canceled; }
			return ret;
		};

		int dummy_status;
		if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(),
		                          dummy_status, std::move(progress), std::move(out),
		                          decompress_)) {
			if (error != Error::Canceled) { error = Error::Read; }
			return false;
		}
	}

	if (res.get_header_value("Connection") == "close" ||
	    (res.version == "HTTP/1.0" && res.reason != "Connection established")) {
		// TODO this requires a not-entirely-obvious chain of calls to be correct
		// for this to be safe. Maybe a code refactor (such as moving this out to
		// the send function and getting rid of the recursiveness of the mutex)
		// could make this more obvious.

		// This is safe to call because process_request is only called by
		// handle_request which is only called by send, which locks the request
		// mutex during the process. It would be a bug to call it from a different
		// thread since it's a thread-safety issue to do these things to the socket
		// if another thread is using the socket.
		std::lock_guard<std::mutex> guard(socket_mutex_);
		shutdown_ssl(socket_, true);
		shutdown_socket(socket_);
		close_socket(socket_);
	}

	// Log
	if (logger_) { logger_(req, res); }

	return true;
}

inline bool
ClientImpl::process_socket(const Socket &socket,
                           std::function<bool(Stream &strm)> callback) {
	return detail::process_client_socket(
	    socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
	    write_timeout_usec_, std::move(callback));
}

inline bool ClientImpl::is_ssl() const { return false; }

inline Result ClientImpl::Get(const char *path) {
	return Get(path, Headers(), Progress());
}

inline Result ClientImpl::Get(const char *path, Progress progress) {
	return Get(path, Headers(), std::move(progress));
}

inline Result ClientImpl::Get(const char *path, const Headers &headers) {
	return Get(path, headers, Progress());
}

inline Result ClientImpl::Get(const char *path, const Headers &headers,
                              Progress progress) {
	Request req;
	req.method = "GET";
	req.path = path;
	req.headers = headers;
	req.progress = std::move(progress);

	return send_(std::move(req));
}

inline Result ClientImpl::Get(const char *path,
                              ContentReceiver content_receiver) {
	return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr);
}

inline Result ClientImpl::Get(const char *path,
                              ContentReceiver content_receiver,
                              Progress progress) {
	return Get(path, Headers(), nullptr, std::move(content_receiver),
	           std::move(progress));
}

inline Result ClientImpl::Get(const char *path, const Headers &headers,
                              ContentReceiver content_receiver) {
	return Get(path, headers, nullptr, std::move(content_receiver), nullptr);
}

inline Result ClientImpl::Get(const char *path, const Headers &headers,
                              ContentReceiver content_receiver,
                              Progress progress) {
	return Get(path, headers, nullptr, std::move(content_receiver),
	           std::move(progress));
}

inline Result ClientImpl::Get(const char *path,
                              ResponseHandler response_handler,
                              ContentReceiver content_receiver) {
	return Get(path, Headers(), std::move(response_handler),
	           std::move(content_receiver), nullptr);
}

inline Result ClientImpl::Get(const char *path, const Headers &headers,
                              ResponseHandler response_handler,
                              ContentReceiver content_receiver) {
	return Get(path, headers, std::move(response_handler),
	           std::move(content_receiver), nullptr);
}

inline Result ClientImpl::Get(const char *path,
                              ResponseHandler response_handler,
                              ContentReceiver content_receiver,
                              Progress progress) {
	return Get(path, Headers(), std::move(response_handler),
	           std::move(content_receiver), std::move(progress));
}

inline Result ClientImpl::Get(const char *path, const Headers &headers,
                              ResponseHandler response_handler,
                              ContentReceiver content_receiver,
                              Progress progress) {
	Request req;
	req.method = "GET";
	req.path = path;
	req.headers = headers;
	req.response_handler = std::move(response_handler);
	req.content_receiver =
	    [content_receiver](const char *data, size_t data_length,
	                       uint64_t /*offset*/, uint64_t /*total_length*/) {
		    return content_receiver(data, data_length);
	    };
	req.progress = std::move(progress);

	return send_(std::move(req));
}

inline Result ClientImpl::Get(const char *path, const Params &params,
                              const Headers &headers, Progress progress) {
	if (params.empty()) { return Get(path, headers); }

	std::string path_with_query = append_query_params(path, params);
	return Get(path_with_query.c_str(), headers, progress);
}

inline Result ClientImpl::Get(const char *path, const Params &params,
                              const Headers &headers,
                              ContentReceiver content_receiver,
                              Progress progress) {
	return Get(path, params, headers, nullptr, content_receiver, progress);
}

inline Result ClientImpl::Get(const char *path, const Params &params,
                              const Headers &headers,
                              ResponseHandler response_handler,
                              ContentReceiver content_receiver,
                              Progress progress) {
	if (params.empty()) {
		return Get(path, headers, response_handler, content_receiver, progress);
	}

	std::string path_with_query = append_query_params(path, params);
	return Get(path_with_query.c_str(), headers, response_handler,
	           content_receiver, progress);
}

inline Result ClientImpl::Head(const char *path) {
	return Head(path, Headers());
}

inline Result ClientImpl::Head(const char *path, const Headers &headers) {
	Request req;
	req.method = "HEAD";
	req.headers = headers;
	req.path = path;

	return send_(std::move(req));
}

inline Result ClientImpl::Post(const char *path) {
	return Post(path, std::string(), nullptr);
}

inline Result ClientImpl::Post(const char *path, const char *body,
                               size_t content_length,
                               const char *content_type) {
	return Post(path, Headers(), body, content_length, content_type);
}

inline Result ClientImpl::Post(const char *path, const Headers &headers,
                               const char *body, size_t content_length,
                               const char *content_type) {
	return send_with_content_provider("POST", path, headers, body, content_length,
	                                  nullptr, nullptr, content_type);
}

inline Result ClientImpl::Post(const char *path, const std::string &body,
                               const char *content_type) {
	return Post(path, Headers(), body, content_type);
}

inline Result ClientImpl::Post(const char *path, const Headers &headers,
                               const std::string &body,
                               const char *content_type) {
	return send_with_content_provider("POST", path, headers, body.data(),
	                                  body.size(), nullptr, nullptr,
	                                  content_type);
}

inline Result ClientImpl::Post(const char *path, const Params &params) {
	return Post(path, Headers(), params);
}

inline Result ClientImpl::Post(const char *path, size_t content_length,
                               ContentProvider content_provider,
                               const char *content_type) {
	return Post(path, Headers(), content_length, std::move(content_provider),
	            content_type);
}

inline Result ClientImpl::Post(const char *path,
                               ContentProviderWithoutLength content_provider,
                               const char *content_type) {
	return Post(path, Headers(), std::move(content_provider), content_type);
}

inline Result ClientImpl::Post(const char *path, const Headers &headers,
                               size_t content_length,
                               ContentProvider content_provider,
                               const char *content_type) {
	return send_with_content_provider("POST", path, headers, nullptr,
	                                  content_length, std::move(content_provider),
	                                  nullptr, content_type);
}

inline Result ClientImpl::Post(const char *path, const Headers &headers,
                               ContentProviderWithoutLength content_provider,
                               const char *content_type) {
	return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr,
	                                  std::move(content_provider), content_type);
}

inline Result ClientImpl::Post(const char *path, const Headers &headers,
                               const Params &params) {
	auto query = detail::params_to_query_str(params);
	return Post(path, headers, query, "application/x-www-form-urlencoded");
}

inline Result ClientImpl::Post(const char *path,
                               const MultipartFormDataItems &items) {
	return Post(path, Headers(), items);
}

inline Result ClientImpl::Post(const char *path, const Headers &headers,
                               const MultipartFormDataItems &items) {
	return Post(path, headers, items, detail::make_multipart_data_boundary());
}
inline Result ClientImpl::Post(const char *path, const Headers &headers,
                               const MultipartFormDataItems &items,
                               const std::string &boundary) {
	for (size_t i = 0; i < boundary.size(); i++) {
		char c = boundary[i];
		if (!std::isalnum(c) && c != '-' && c != '_') {
			return Result{nullptr, Error::UnsupportedMultipartBoundaryChars};
		}
	}

	std::string body;

	for (const auto &item : items) {
		body += "--" + boundary + "\r\n";
		body += "Content-Disposition: form-data; name=\"" + item.name + "\"";
		if (!item.filename.empty()) {
			body += "; filename=\"" + item.filename + "\"";
		}
		body += "\r\n";
		if (!item.content_type.empty()) {
			body += "Content-Type: " + item.content_type + "\r\n";
		}
		body += "\r\n";
		body += item.content + "\r\n";
	}

	body += "--" + boundary + "--\r\n";

	std::string content_type = "multipart/form-data; boundary=" + boundary;
	return Post(path, headers, body, content_type.c_str());
}

inline Result ClientImpl::Put(const char *path) {
	return Put(path, std::string(), nullptr);
}

inline Result ClientImpl::Put(const char *path, const char *body,
                              size_t content_length, const char *content_type) {
	return Put(path, Headers(), body, content_length, content_type);
}

inline Result ClientImpl::Put(const char *path, const Headers &headers,
                              const char *body, size_t content_length,
                              const char *content_type) {
	return send_with_content_provider("PUT", path, headers, body, content_length,
	                                  nullptr, nullptr, content_type);
}

inline Result ClientImpl::Put(const char *path, const std::string &body,
                              const char *content_type) {
	return Put(path, Headers(), body, content_type);
}

inline Result ClientImpl::Put(const char *path, const Headers &headers,
                              const std::string &body,
                              const char *content_type) {
	return send_with_content_provider("PUT", path, headers, body.data(),
	                                  body.size(), nullptr, nullptr,
	                                  content_type);
}

inline Result ClientImpl::Put(const char *path, size_t content_length,
                              ContentProvider content_provider,
                              const char *content_type) {
	return Put(path, Headers(), content_length, std::move(content_provider),
	           content_type);
}

inline Result ClientImpl::Put(const char *path,
                              ContentProviderWithoutLength content_provider,
                              const char *content_type) {
	return Put(path, Headers(), std::move(content_provider), content_type);
}

inline Result ClientImpl::Put(const char *path, const Headers &headers,
                              size_t content_length,
                              ContentProvider content_provider,
                              const char *content_type) {
	return send_with_content_provider("PUT", path, headers, nullptr,
	                                  content_length, std::move(content_provider),
	                                  nullptr, content_type);
}

inline Result ClientImpl::Put(const char *path, const Headers &headers,
                              ContentProviderWithoutLength content_provider,
                              const char *content_type) {
	return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr,
	                                  std::move(content_provider), content_type);
}

inline Result ClientImpl::Put(const char *path, const Params &params) {
	return Put(path, Headers(), params);
}

inline Result ClientImpl::Put(const char *path, const Headers &headers,
                              const Params &params) {
	auto query = detail::params_to_query_str(params);
	return Put(path, headers, query, "application/x-www-form-urlencoded");
}

inline Result ClientImpl::Patch(const char *path) {
	return Patch(path, std::string(), nullptr);
}

inline Result ClientImpl::Patch(const char *path, const char *body,
                                size_t content_length,
                                const char *content_type) {
	return Patch(path, Headers(), body, content_length, content_type);
}

inline Result ClientImpl::Patch(const char *path, const Headers &headers,
                                const char *body, size_t content_length,
                                const char *content_type) {
	return send_with_content_provider("PATCH", path, headers, body,
	                                  content_length, nullptr, nullptr,
	                                  content_type);
}

inline Result ClientImpl::Patch(const char *path, const std::string &body,
                                const char *content_type) {
	return Patch(path, Headers(), body, content_type);
}

inline Result ClientImpl::Patch(const char *path, const Headers &headers,
                                const std::string &body,
                                const char *content_type) {
	return send_with_content_provider("PATCH", path, headers, body.data(),
	                                  body.size(), nullptr, nullptr,
	                                  content_type);
}

inline Result ClientImpl::Patch(const char *path, size_t content_length,
                                ContentProvider content_provider,
                                const char *content_type) {
	return Patch(path, Headers(), content_length, std::move(content_provider),
	             content_type);
}

inline Result ClientImpl::Patch(const char *path,
                                ContentProviderWithoutLength content_provider,
                                const char *content_type) {
	return Patch(path, Headers(), std::move(content_provider), content_type);
}

inline Result ClientImpl::Patch(const char *path, const Headers &headers,
                                size_t content_length,
                                ContentProvider content_provider,
                                const char *content_type) {
	return send_with_content_provider("PATCH", path, headers, nullptr,
	                                  content_length, std::move(content_provider),
	                                  nullptr, content_type);
}

inline Result ClientImpl::Patch(const char *path, const Headers &headers,
                                ContentProviderWithoutLength content_provider,
                                const char *content_type) {
	return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr,
	                                  std::move(content_provider), content_type);
}

inline Result ClientImpl::Delete(const char *path) {
	return Delete(path, Headers(), std::string(), nullptr);
}

inline Result ClientImpl::Delete(const char *path, const Headers &headers) {
	return Delete(path, headers, std::string(), nullptr);
}

inline Result ClientImpl::Delete(const char *path, const char *body,
                                 size_t content_length,
                                 const char *content_type) {
	return Delete(path, Headers(), body, content_length, content_type);
}

inline Result ClientImpl::Delete(const char *path, const Headers &headers,
                                 const char *body, size_t content_length,
                                 const char *content_type) {
	Request req;
	req.method = "DELETE";
	req.headers = headers;
	req.path = path;

	if (content_type) { req.headers.emplace("Content-Type", content_type); }
	req.body.assign(body, content_length);

	return send_(std::move(req));
}

inline Result ClientImpl::Delete(const char *path, const std::string &body,
                                 const char *content_type) {
	return Delete(path, Headers(), body.data(), body.size(), content_type);
}

inline Result ClientImpl::Delete(const char *path, const Headers &headers,
                                 const std::string &body,
                                 const char *content_type) {
	return Delete(path, headers, body.data(), body.size(), content_type);
}

inline Result ClientImpl::Options(const char *path) {
	return Options(path, Headers());
}

inline Result ClientImpl::Options(const char *path, const Headers &headers) {
	Request req;
	req.method = "OPTIONS";
	req.headers = headers;
	req.path = path;

	return send_(std::move(req));
}

inline size_t ClientImpl::is_socket_open() const {
	std::lock_guard<std::mutex> guard(socket_mutex_);
	return socket_.is_open();
}

inline void ClientImpl::stop() {
	std::lock_guard<std::mutex> guard(socket_mutex_);

	// If there is anything ongoing right now, the ONLY thread-safe thing we can
	// do is to shutdown_socket, so that threads using this socket suddenly
	// discover they can't read/write any more and error out. Everything else
	// (closing the socket, shutting ssl down) is unsafe because these actions are
	// not thread-safe.
	if (socket_requests_in_flight_ > 0) {
		shutdown_socket(socket_);

		// Aside from that, we set a flag for the socket to be closed when we're
		// done.
		socket_should_be_closed_when_request_is_done_ = true;
		return;
	}

	// Otherwise, sitll holding the mutex, we can shut everything down ourselves
	shutdown_ssl(socket_, true);
	shutdown_socket(socket_);
	close_socket(socket_);
}

inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
	connection_timeout_sec_ = sec;
	connection_timeout_usec_ = usec;
}

inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) {
	read_timeout_sec_ = sec;
	read_timeout_usec_ = usec;
}

inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
	write_timeout_sec_ = sec;
	write_timeout_usec_ = usec;
}

inline void ClientImpl::set_basic_auth(const char *username,
                                       const char *password) {
	basic_auth_username_ = username;
	basic_auth_password_ = password;
}

inline void ClientImpl::set_bearer_token_auth(const char *token) {
	bearer_token_auth_token_ = token;
}

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void ClientImpl::set_digest_auth(const char *username,
                                        const char *password) {
	digest_auth_username_ = username;
	digest_auth_password_ = password;
}
#endif

inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; }

inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }

inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }

inline void ClientImpl::set_hostname_addr_map(
    const std::map<std::string, std::string> addr_map) {
	addr_map_ = std::move(addr_map);
}

inline void ClientImpl::set_default_headers(Headers headers) {
	default_headers_ = std::move(headers);
}

inline void ClientImpl::set_address_family(int family) {
	address_family_ = family;
}

inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }

inline void ClientImpl::set_socket_options(SocketOptions socket_options) {
	socket_options_ = std::move(socket_options);
}

inline void ClientImpl::set_compress(bool on) { compress_ = on; }

inline void ClientImpl::set_decompress(bool on) { decompress_ = on; }

inline void ClientImpl::set_interface(const char *intf) { interface_ = intf; }

inline void ClientImpl::set_proxy(const char *host, int port) {
	proxy_host_ = host;
	proxy_port_ = port;
}

inline void ClientImpl::set_proxy_basic_auth(const char *username,
                                             const char *password) {
	proxy_basic_auth_username_ = username;
	proxy_basic_auth_password_ = password;
}

inline void ClientImpl::set_proxy_bearer_token_auth(const char *token) {
	proxy_bearer_token_auth_token_ = token;
}

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void ClientImpl::set_proxy_digest_auth(const char *username,
                                              const char *password) {
	proxy_digest_auth_username_ = username;
	proxy_digest_auth_password_ = password;
}
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void ClientImpl::set_ca_cert_path(const char *ca_cert_file_path,
                                         const char *ca_cert_dir_path) {
	if (ca_cert_file_path) { ca_cert_file_path_ = ca_cert_file_path; }
	if (ca_cert_dir_path) { ca_cert_dir_path_ = ca_cert_dir_path; }
}

inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
	if (ca_cert_store && ca_cert_store != ca_cert_store_) {
		ca_cert_store_ = ca_cert_store;
	}
}
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
	server_certificate_verification_ = enabled;
}
#endif

inline void ClientImpl::set_logger(Logger logger) {
	logger_ = std::move(logger);
}

/*
 * SSL Implementation
 */
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
namespace detail {

template <typename U, typename V>
inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex,
                    U SSL_connect_or_accept, V setup) {
	SSL *ssl = nullptr;
	{
		std::lock_guard<std::mutex> guard(ctx_mutex);
		ssl = SSL_new(ctx);
	}

	if (ssl) {
		set_nonblocking(sock, true);
		auto bio = BIO_new_socket(static_cast<int>(sock), BIO_NOCLOSE);
		BIO_set_nbio(bio, 1);
		SSL_set_bio(ssl, bio, bio);

		if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) {
			SSL_shutdown(ssl);
			{
				std::lock_guard<std::mutex> guard(ctx_mutex);
				SSL_free(ssl);
			}
			set_nonblocking(sock, false);
			return nullptr;
		}
		BIO_set_nbio(bio, 0);
		set_nonblocking(sock, false);
	}

	return ssl;
}

inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl,
                       bool shutdown_gracefully) {
	// sometimes we may want to skip this to try to avoid SIGPIPE if we know
	// the remote has closed the network connection
	// Note that it is not always possible to avoid SIGPIPE, this is merely a
	// best-efforts.
	if (shutdown_gracefully) { SSL_shutdown(ssl); }

	std::lock_guard<std::mutex> guard(ctx_mutex);
	SSL_free(ssl);
}

template <typename U>
bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl,
                                       U ssl_connect_or_accept,
                                       time_t timeout_sec,
                                       time_t timeout_usec) {
	int res = 0;
	while ((res = ssl_connect_or_accept(ssl)) != 1) {
		auto err = SSL_get_error(ssl, res);
		switch (err) {
		case SSL_ERROR_WANT_READ:
			if (select_read(sock, timeout_sec, timeout_usec) > 0) { continue; }
			break;
		case SSL_ERROR_WANT_WRITE:
			if (select_write(sock, timeout_sec, timeout_usec) > 0) { continue; }
			break;
		default: break;
		}
		return false;
	}
	return true;
}

template <typename T>
inline bool process_server_socket_ssl(
    const std::atomic<socket_t> &svr_sock, SSL *ssl, socket_t sock,
    size_t keep_alive_max_count, time_t keep_alive_timeout_sec,
    time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
    time_t write_timeout_usec, T callback) {
	return process_server_socket_core(
	    svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
	    [&](bool close_connection, bool &connection_closed) {
		    SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
		                         write_timeout_sec, write_timeout_usec);
		    return callback(strm, close_connection, connection_closed);
	    });
}

template <typename T>
inline bool
process_client_socket_ssl(SSL *ssl, socket_t sock, time_t read_timeout_sec,
                          time_t read_timeout_usec, time_t write_timeout_sec,
                          time_t write_timeout_usec, T callback) {
	SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
	                     write_timeout_sec, write_timeout_usec);
	return callback(strm);
}

#if OPENSSL_VERSION_NUMBER < 0x10100000L
static std::shared_ptr<std::vector<std::mutex>> openSSL_locks_;

class SSLThreadLocks {
public:
	SSLThreadLocks() {
		openSSL_locks_ =
		    std::make_shared<std::vector<std::mutex>>(CRYPTO_num_locks());
		CRYPTO_set_locking_callback(locking_callback);
	}

	~SSLThreadLocks() { CRYPTO_set_locking_callback(nullptr); }

private:
	static void locking_callback(int mode, int type, const char * /*file*/,
	                             int /*line*/) {
		auto &lk = (*openSSL_locks_)[static_cast<size_t>(type)];
		if (mode & CRYPTO_LOCK) {
			lk.lock();
		} else {
			lk.unlock();
		}
	}
};

#endif

class SSLInit {
public:
	SSLInit() {
#if OPENSSL_VERSION_NUMBER < 0x1010001fL
		SSL_load_error_strings();
		SSL_library_init();
#else
		OPENSSL_init_ssl(
		    OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
#endif
	}

	~SSLInit() {
#if OPENSSL_VERSION_NUMBER < 0x1010001fL
		ERR_free_strings();
#endif
	}

private:
#if OPENSSL_VERSION_NUMBER < 0x10100000L
	SSLThreadLocks thread_init_;
#endif
};

// SSL socket stream implementation
inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl,
                                        time_t read_timeout_sec,
                                        time_t read_timeout_usec,
                                        time_t write_timeout_sec,
                                        time_t write_timeout_usec)
    : sock_(sock), ssl_(ssl), read_timeout_sec_(read_timeout_sec),
      read_timeout_usec_(read_timeout_usec),
      write_timeout_sec_(write_timeout_sec),
      write_timeout_usec_(write_timeout_usec) {
	SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
}

inline SSLSocketStream::~SSLSocketStream() {}

inline bool SSLSocketStream::is_readable() const {
	return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
}

inline bool SSLSocketStream::is_writable() const {
	return detail::select_write(sock_, write_timeout_sec_, write_timeout_usec_) >
	       0;
}

inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
	if (SSL_pending(ssl_) > 0) {
		return SSL_read(ssl_, ptr, static_cast<int>(size));
	} else if (is_readable()) {
		auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
		if (ret < 0) {
			auto err = SSL_get_error(ssl_, ret);
			int n = 1000;
#ifdef _WIN32
			while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
			                    (err == SSL_ERROR_SYSCALL &&
			                     WSAGetLastError() == WSAETIMEDOUT))) {
#else
			while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
#endif
				if (SSL_pending(ssl_) > 0) {
					return SSL_read(ssl_, ptr, static_cast<int>(size));
				} else if (is_readable()) {
					std::this_thread::sleep_for(std::chrono::milliseconds(1));
					ret = SSL_read(ssl_, ptr, static_cast<int>(size));
					if (ret >= 0) { return ret; }
					err = SSL_get_error(ssl_, ret);
				} else {
					return -1;
				}
			}
		}
		return ret;
	}
	return -1;
}

inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
	if (is_writable()) {
		auto ret = SSL_write(ssl_, ptr, static_cast<int>(size));
		if (ret < 0) {
			auto err = SSL_get_error(ssl_, ret);
			int n = 1000;
#ifdef _WIN32
			while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
			                    (err == SSL_ERROR_SYSCALL &&
			                     WSAGetLastError() == WSAETIMEDOUT))) {
#else
			while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
#endif
				if (is_writable()) {
					std::this_thread::sleep_for(std::chrono::milliseconds(1));
					ret = SSL_write(ssl_, ptr, static_cast<int>(size));
					if (ret >= 0) { return ret; }
					err = SSL_get_error(ssl_, ret);
				} else {
					return -1;
				}
			}
		}
		return ret;
	}
	return -1;
}

inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip,
                                                    int &port) const {
	detail::get_remote_ip_and_port(sock_, ip, port);
}

inline socket_t SSLSocketStream::socket() const { return sock_; }

static SSLInit sslinit_;

} // namespace detail

// SSL HTTP server implementation
inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
                            const char *client_ca_cert_file_path,
                            const char *client_ca_cert_dir_path) {
	ctx_ = SSL_CTX_new(TLS_server_method());

	if (ctx_) {
		SSL_CTX_set_options(ctx_,
		                    SSL_OP_NO_COMPRESSION |
		                        SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);

		SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION);

		if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
		    SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) !=
		        1) {
			SSL_CTX_free(ctx_);
			ctx_ = nullptr;
		} else if (client_ca_cert_file_path || client_ca_cert_dir_path) {
			SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path,
			                              client_ca_cert_dir_path);

			SSL_CTX_set_verify(
			    ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
		}
	}
}

inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key,
                            X509_STORE *client_ca_cert_store) {
	ctx_ = SSL_CTX_new(TLS_server_method());

	if (ctx_) {
		SSL_CTX_set_options(ctx_,
		                    SSL_OP_NO_COMPRESSION |
		                        SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);

		SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION);

		if (SSL_CTX_use_certificate(ctx_, cert) != 1 ||
		    SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) {
			SSL_CTX_free(ctx_);
			ctx_ = nullptr;
		} else if (client_ca_cert_store) {
			SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);

			SSL_CTX_set_verify(
			    ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
		}
	}
}

inline SSLServer::SSLServer(
    const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback) {
	ctx_ = SSL_CTX_new(TLS_method());
	if (ctx_) {
		if (!setup_ssl_ctx_callback(*ctx_)) {
			SSL_CTX_free(ctx_);
			ctx_ = nullptr;
		}
	}
}

inline SSLServer::~SSLServer() {
	if (ctx_) { SSL_CTX_free(ctx_); }
}

inline bool SSLServer::is_valid() const { return ctx_; }

inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }

inline bool SSLServer::process_and_close_socket(socket_t sock) {
	auto ssl = detail::ssl_new(
	    sock, ctx_, ctx_mutex_,
	    [&](SSL *ssl) {
		    return detail::ssl_connect_or_accept_nonblocking(
		        sock, ssl, SSL_accept, read_timeout_sec_, read_timeout_usec_);
	    },
	    [](SSL * /*ssl*/) { return true; });

	bool ret = false;
	if (ssl) {
		ret = detail::process_server_socket_ssl(
		    svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
		    read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
		    write_timeout_usec_,
		    [this, ssl](Stream &strm, bool close_connection,
		                bool &connection_closed) {
			    return process_request(strm, close_connection, connection_closed,
			                           [&](Request &req) { req.ssl = ssl; });
		    });

		// Shutdown gracefully if the result seemed successful, non-gracefully if
		// the connection appeared to be closed.
		const bool shutdown_gracefully = ret;
		detail::ssl_delete(ctx_mutex_, ssl, shutdown_gracefully);
	}

	detail::shutdown_socket(sock);
	detail::close_socket(sock);
	return ret;
}

// SSL HTTP client implementation
inline SSLClient::SSLClient(const std::string &host)
    : SSLClient(host, 443, std::string(), std::string()) {}

inline SSLClient::SSLClient(const std::string &host, int port)
    : SSLClient(host, port, std::string(), std::string()) {}

inline SSLClient::SSLClient(const std::string &host, int port,
                            const std::string &client_cert_path,
                            const std::string &client_key_path)
    : ClientImpl(host, port, client_cert_path, client_key_path) {
	ctx_ = SSL_CTX_new(TLS_client_method());

	detail::split(&host_[0], &host_[host_.size()], '.',
	              [&](const char *b, const char *e) {
		              host_components_.emplace_back(std::string(b, e));
	              });

	if (!client_cert_path.empty() && !client_key_path.empty()) {
		if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(),
		                                 SSL_FILETYPE_PEM) != 1 ||
		    SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(),
		                                SSL_FILETYPE_PEM) != 1) {
			SSL_CTX_free(ctx_);
			ctx_ = nullptr;
		}
	}
}

inline SSLClient::SSLClient(const std::string &host, int port,
                            X509 *client_cert, EVP_PKEY *client_key)
    : ClientImpl(host, port) {
	ctx_ = SSL_CTX_new(TLS_client_method());

	detail::split(&host_[0], &host_[host_.size()], '.',
	              [&](const char *b, const char *e) {
		              host_components_.emplace_back(std::string(b, e));
	              });

	if (client_cert != nullptr && client_key != nullptr) {
		if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 ||
		    SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) {
			SSL_CTX_free(ctx_);
			ctx_ = nullptr;
		}
	}
}

inline SSLClient::~SSLClient() {
	if (ctx_) { SSL_CTX_free(ctx_); }
	// Make sure to shut down SSL since shutdown_ssl will resolve to the
	// base function rather than the derived function once we get to the
	// base class destructor, and won't free the SSL (causing a leak).
	shutdown_ssl_impl(socket_, true);
}

inline bool SSLClient::is_valid() const { return ctx_; }

inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
	if (ca_cert_store) {
		if (ctx_) {
			if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store) {
				// Free memory allocated for old cert and use new store `ca_cert_store`
				SSL_CTX_set_cert_store(ctx_, ca_cert_store);
			}
		} else {
			X509_STORE_free(ca_cert_store);
		}
	}
}

inline long SSLClient::get_openssl_verify_result() const {
	return verify_result_;
}

inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; }

inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) {
	return is_valid() && ClientImpl::create_and_connect_socket(socket, error);
}

// Assumes that socket_mutex_ is locked and that there are no requests in flight
inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
                                          bool &success, Error &error) {
	success = true;
	Response res2;
	if (!detail::process_client_socket(
	        socket.sock, read_timeout_sec_, read_timeout_usec_,
	        write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
		        Request req2;
		        req2.method = "CONNECT";
		        req2.path = host_and_port_;
		        return process_request(strm, req2, res2, false, error);
	        })) {
		// Thread-safe to close everything because we are assuming there are no
		// requests in flight
		shutdown_ssl(socket, true);
		shutdown_socket(socket);
		close_socket(socket);
		success = false;
		return false;
	}

	if (res2.status == 407) {
		if (!proxy_digest_auth_username_.empty() &&
		    !proxy_digest_auth_password_.empty()) {
			std::map<std::string, std::string> auth;
			if (detail::parse_www_authenticate(res2, auth, true)) {
				Response res3;
				if (!detail::process_client_socket(
				        socket.sock, read_timeout_sec_, read_timeout_usec_,
				        write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
					        Request req3;
					        req3.method = "CONNECT";
					        req3.path = host_and_port_;
					        req3.headers.insert(detail::make_digest_authentication_header(
					            req3, auth, 1, detail::random_string(10),
					            proxy_digest_auth_username_, proxy_digest_auth_password_,
					            true));
					        return process_request(strm, req3, res3, false, error);
				        })) {
					// Thread-safe to close everything because we are assuming there are
					// no requests in flight
					shutdown_ssl(socket, true);
					shutdown_socket(socket);
					close_socket(socket);
					success = false;
					return false;
				}
			}
		} else {
			res = res2;
			return false;
		}
	}

	return true;
}

inline bool SSLClient::load_certs() {
	bool ret = true;

	std::call_once(initialize_cert_, [&]() {
		std::lock_guard<std::mutex> guard(ctx_mutex_);
		if (!ca_cert_file_path_.empty()) {
			if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
			                                   nullptr)) {
				ret = false;
			}
		} else if (!ca_cert_dir_path_.empty()) {
			if (!SSL_CTX_load_verify_locations(ctx_, nullptr,
			                                   ca_cert_dir_path_.c_str())) {
				ret = false;
			}
		} else {
#ifdef _WIN32
			detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_));
#else
			    SSL_CTX_set_default_verify_paths(ctx_);
#endif
		}
	});

	return ret;
}

inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
	auto ssl = detail::ssl_new(
	    socket.sock, ctx_, ctx_mutex_,
	    [&](SSL *ssl) {
		    if (server_certificate_verification_) {
			    if (!load_certs()) {
				    error = Error::SSLLoadingCerts;
				    return false;
			    }
			    SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr);
		    }

		    if (!detail::ssl_connect_or_accept_nonblocking(
		            socket.sock, ssl, SSL_connect, connection_timeout_sec_,
		            connection_timeout_usec_)) {
			    error = Error::SSLConnection;
			    return false;
		    }

		    if (server_certificate_verification_) {
			    verify_result_ = SSL_get_verify_result(ssl);

			    if (verify_result_ != X509_V_OK) {
				    error = Error::SSLServerVerification;
				    return false;
			    }

			    auto server_cert = SSL_get_peer_certificate(ssl);

			    if (server_cert == nullptr) {
				    error = Error::SSLServerVerification;
				    return false;
			    }

			    if (!verify_host(server_cert)) {
				    X509_free(server_cert);
				    error = Error::SSLServerVerification;
				    return false;
			    }
			    X509_free(server_cert);
		    }

		    return true;
	    },
	    [&](SSL *ssl) {
		    SSL_set_tlsext_host_name(ssl, host_.c_str());
		    return true;
	    });

	if (ssl) {
		socket.ssl = ssl;
		return true;
	}

	shutdown_socket(socket);
	close_socket(socket);
	return false;
}

inline void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) {
	shutdown_ssl_impl(socket, shutdown_gracefully);
}

inline void SSLClient::shutdown_ssl_impl(Socket &socket,
                                         bool shutdown_gracefully) {
	if (socket.sock == INVALID_SOCKET) {
		assert(socket.ssl == nullptr);
		return;
	}
	if (socket.ssl) {
		detail::ssl_delete(ctx_mutex_, socket.ssl, shutdown_gracefully);
		socket.ssl = nullptr;
	}
	assert(socket.ssl == nullptr);
}

inline bool
SSLClient::process_socket(const Socket &socket,
                          std::function<bool(Stream &strm)> callback) {
	assert(socket.ssl);
	return detail::process_client_socket_ssl(
	    socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_,
	    write_timeout_sec_, write_timeout_usec_, std::move(callback));
}

inline bool SSLClient::is_ssl() const { return true; }

inline bool SSLClient::verify_host(X509 *server_cert) const {
	/* Quote from RFC2818 section 3.1 "Server Identity"

	   If a subjectAltName extension of type dNSName is present, that MUST
	   be used as the identity. Otherwise, the (most specific) Common Name
	   field in the Subject field of the certificate MUST be used. Although
	   the use of the Common Name is existing practice, it is deprecated and
	   Certification Authorities are encouraged to use the dNSName instead.

	   Matching is performed using the matching rules specified by
	   [RFC2459].  If more than one identity of a given type is present in
	   the certificate (e.g., more than one dNSName name, a match in any one
	   of the set is considered acceptable.) Names may contain the wildcard
	   character * which is considered to match any single domain name
	   component or component fragment. E.g., *.a.com matches foo.a.com but
	   not bar.foo.a.com. f*.com matches foo.com but not bar.com.

	   In some cases, the URI is specified as an IP address rather than a
	   hostname. In this case, the iPAddress subjectAltName must be present
	   in the certificate and must exactly match the IP in the URI.

	*/
	return verify_host_with_subject_alt_name(server_cert) ||
	       verify_host_with_common_name(server_cert);
}

inline bool
SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
	auto ret = false;

	auto type = GEN_DNS;

	struct in6_addr addr6;
	struct in_addr addr;
	size_t addr_len = 0;

#ifndef __MINGW32__
	if (inet_pton(AF_INET6, host_.c_str(), &addr6)) {
		type = GEN_IPADD;
		addr_len = sizeof(struct in6_addr);
	} else if (inet_pton(AF_INET, host_.c_str(), &addr)) {
		type = GEN_IPADD;
		addr_len = sizeof(struct in_addr);
	}
#endif

	auto alt_names = static_cast<const struct stack_st_GENERAL_NAME *>(
	    X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr));

	if (alt_names) {
		auto dsn_matched = false;
		auto ip_mached = false;

		auto count = sk_GENERAL_NAME_num(alt_names);

		for (decltype(count) i = 0; i < count && !dsn_matched; i++) {
			auto val = sk_GENERAL_NAME_value(alt_names, i);
			if (val->type == type) {
				auto name = (const char *)ASN1_STRING_get0_data(val->d.ia5);
				auto name_len = (size_t)ASN1_STRING_length(val->d.ia5);

				switch (type) {
				case GEN_DNS: dsn_matched = check_host_name(name, name_len); break;

				case GEN_IPADD:
					if (!memcmp(&addr6, name, addr_len) ||
					    !memcmp(&addr, name, addr_len)) {
						ip_mached = true;
					}
					break;
				}
			}
		}

		if (dsn_matched || ip_mached) { ret = true; }
	}

	GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names);
	return ret;
}

inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const {
	const auto subject_name = X509_get_subject_name(server_cert);

	if (subject_name != nullptr) {
		char name[BUFSIZ];
		auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
		                                          name, sizeof(name));

		if (name_len != -1) {
			return check_host_name(name, static_cast<size_t>(name_len));
		}
	}

	return false;
}

inline bool SSLClient::check_host_name(const char *pattern,
                                       size_t pattern_len) const {
	if (host_.size() == pattern_len && host_ == pattern) { return true; }

	// Wildcard match
	// https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484
	std::vector<std::string> pattern_components;
	detail::split(&pattern[0], &pattern[pattern_len], '.',
	              [&](const char *b, const char *e) {
		              pattern_components.emplace_back(std::string(b, e));
	              });

	if (host_components_.size() != pattern_components.size()) { return false; }

	auto itr = pattern_components.begin();
	for (const auto &h : host_components_) {
		auto &p = *itr;
		if (p != h && p != "*") {
			auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' &&
			                      !p.compare(0, p.size() - 1, h));
			if (!partial_match) { return false; }
		}
		++itr;
	}

	return true;
}
#endif

// Universal client implementation
inline Client::Client(const std::string &scheme_host_port)
    : Client(scheme_host_port, std::string(), std::string()) {}

inline Client::Client(const std::string &scheme_host_port,
                      const std::string &client_cert_path,
                      const std::string &client_key_path) {
	const static Regex re(
	    R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)");

	Match m;
	if (duckdb_re2::RegexMatch(scheme_host_port, m, re)) {
		auto scheme = m[1].str();

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
		if (!scheme.empty() && (scheme != "http" && scheme != "https")) {
#else
		if (!scheme.empty() && scheme != "http") {
#endif
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
			std::string msg = "'" + scheme + "' scheme is not supported.";
			throw std::invalid_argument(msg);
#endif
			return;
		}

		auto is_ssl = scheme == "https";

		auto host = m[2].str();
		if (host.empty()) { host = m[3].str(); }

		auto port_str = m[4].str();
		auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);

		if (is_ssl) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
			cli_ = detail::make_unique<SSLClient>(host.c_str(), port,
			                                      client_cert_path, client_key_path);
			is_ssl_ = is_ssl;
#endif
		} else {
			cli_ = detail::make_unique<ClientImpl>(host.c_str(), port,
			                                       client_cert_path, client_key_path);
		}
	} else {
		cli_ = detail::make_unique<ClientImpl>(scheme_host_port, 80,
		                                       client_cert_path, client_key_path);
	}
}

inline Client::Client(const std::string &host, int port)
    : cli_(detail::make_unique<ClientImpl>(host, port)) {}

inline Client::Client(const std::string &host, int port,
                      const std::string &client_cert_path,
                      const std::string &client_key_path)
    : cli_(detail::make_unique<ClientImpl>(host, port, client_cert_path,
                                           client_key_path)) {}

inline Client::~Client() {}

inline bool Client::is_valid() const {
	return cli_ != nullptr && cli_->is_valid();
}

inline Result Client::Get(const char *path) { return cli_->Get(path); }
inline Result Client::Get(const char *path, const Headers &headers) {
	return cli_->Get(path, headers);
}
inline Result Client::Get(const char *path, Progress progress) {
	return cli_->Get(path, std::move(progress));
}
inline Result Client::Get(const char *path, const Headers &headers,
                          Progress progress) {
	return cli_->Get(path, headers, std::move(progress));
}
inline Result Client::Get(const char *path, ContentReceiver content_receiver) {
	return cli_->Get(path, std::move(content_receiver));
}
inline Result Client::Get(const char *path, const Headers &headers,
                          ContentReceiver content_receiver) {
	return cli_->Get(path, headers, std::move(content_receiver));
}
inline Result Client::Get(const char *path, ContentReceiver content_receiver,
                          Progress progress) {
	return cli_->Get(path, std::move(content_receiver), std::move(progress));
}
inline Result Client::Get(const char *path, const Headers &headers,
                          ContentReceiver content_receiver, Progress progress) {
	return cli_->Get(path, headers, std::move(content_receiver),
	                 std::move(progress));
}
inline Result Client::Get(const char *path, ResponseHandler response_handler,
                          ContentReceiver content_receiver) {
	return cli_->Get(path, std::move(response_handler),
	                 std::move(content_receiver));
}
inline Result Client::Get(const char *path, const Headers &headers,
                          ResponseHandler response_handler,
                          ContentReceiver content_receiver) {
	return cli_->Get(path, headers, std::move(response_handler),
	                 std::move(content_receiver));
}
inline Result Client::Get(const char *path, ResponseHandler response_handler,
                          ContentReceiver content_receiver, Progress progress) {
	return cli_->Get(path, std::move(response_handler),
	                 std::move(content_receiver), std::move(progress));
}
inline Result Client::Get(const char *path, const Headers &headers,
                          ResponseHandler response_handler,
                          ContentReceiver content_receiver, Progress progress) {
	return cli_->Get(path, headers, std::move(response_handler),
	                 std::move(content_receiver), std::move(progress));
}
inline Result Client::Get(const char *path, const Params &params,
                          const Headers &headers, Progress progress) {
	return cli_->Get(path, params, headers, progress);
}
inline Result Client::Get(const char *path, const Params &params,
                          const Headers &headers,
                          ContentReceiver content_receiver, Progress progress) {
	return cli_->Get(path, params, headers, content_receiver, progress);
}
inline Result Client::Get(const char *path, const Params &params,
                          const Headers &headers,
                          ResponseHandler response_handler,
                          ContentReceiver content_receiver, Progress progress) {
	return cli_->Get(path, params, headers, response_handler, content_receiver,
	                 progress);
}

inline Result Client::Head(const char *path) { return cli_->Head(path); }
inline Result Client::Head(const char *path, const Headers &headers) {
	return cli_->Head(path, headers);
}

inline Result Client::Post(const char *path) { return cli_->Post(path); }
inline Result Client::Post(const char *path, const char *body,
                           size_t content_length, const char *content_type) {
	return cli_->Post(path, body, content_length, content_type);
}
inline Result Client::Post(const char *path, const Headers &headers,
                           const char *body, size_t content_length,
                           const char *content_type) {
	return cli_->Post(path, headers, body, content_length, content_type);
}
inline Result Client::Post(const char *path, const std::string &body,
                           const char *content_type) {
	return cli_->Post(path, body, content_type);
}
inline Result Client::Post(const char *path, const Headers &headers,
                           const std::string &body, const char *content_type) {
	return cli_->Post(path, headers, body, content_type);
}
inline Result Client::Post(const char *path, size_t content_length,
                           ContentProvider content_provider,
                           const char *content_type) {
	return cli_->Post(path, content_length, std::move(content_provider),
	                  content_type);
}
inline Result Client::Post(const char *path,
                           ContentProviderWithoutLength content_provider,
                           const char *content_type) {
	return cli_->Post(path, std::move(content_provider), content_type);
}
inline Result Client::Post(const char *path, const Headers &headers,
                           size_t content_length,
                           ContentProvider content_provider,
                           const char *content_type) {
	return cli_->Post(path, headers, content_length, std::move(content_provider),
	                  content_type);
}
inline Result Client::Post(const char *path, const Headers &headers,
                           ContentProviderWithoutLength content_provider,
                           const char *content_type) {
	return cli_->Post(path, headers, std::move(content_provider), content_type);
}
inline Result Client::Post(const char *path, const Params &params) {
	return cli_->Post(path, params);
}
inline Result Client::Post(const char *path, const Headers &headers,
                           const Params &params) {
	return cli_->Post(path, headers, params);
}
inline Result Client::Post(const char *path,
                           const MultipartFormDataItems &items) {
	return cli_->Post(path, items);
}
inline Result Client::Post(const char *path, const Headers &headers,
                           const MultipartFormDataItems &items) {
	return cli_->Post(path, headers, items);
}
inline Result Client::Post(const char *path, const Headers &headers,
                           const MultipartFormDataItems &items,
                           const std::string &boundary) {
	return cli_->Post(path, headers, items, boundary);
}
inline Result Client::Put(const char *path) { return cli_->Put(path); }
inline Result Client::Put(const char *path, const char *body,
                          size_t content_length, const char *content_type) {
	return cli_->Put(path, body, content_length, content_type);
}
inline Result Client::Put(const char *path, const Headers &headers,
                          const char *body, size_t content_length,
                          const char *content_type) {
	return cli_->Put(path, headers, body, content_length, content_type);
}
inline Result Client::Put(const char *path, const std::string &body,
                          const char *content_type) {
	return cli_->Put(path, body, content_type);
}
inline Result Client::Put(const char *path, const Headers &headers,
                          const std::string &body, const char *content_type) {
	return cli_->Put(path, headers, body, content_type);
}
inline Result Client::Put(const char *path, size_t content_length,
                          ContentProvider content_provider,
                          const char *content_type) {
	return cli_->Put(path, content_length, std::move(content_provider),
	                 content_type);
}
inline Result Client::Put(const char *path,
                          ContentProviderWithoutLength content_provider,
                          const char *content_type) {
	return cli_->Put(path, std::move(content_provider), content_type);
}
inline Result Client::Put(const char *path, const Headers &headers,
                          size_t content_length,
                          ContentProvider content_provider,
                          const char *content_type) {
	return cli_->Put(path, headers, content_length, std::move(content_provider),
	                 content_type);
}
inline Result Client::Put(const char *path, const Headers &headers,
                          ContentProviderWithoutLength content_provider,
                          const char *content_type) {
	return cli_->Put(path, headers, std::move(content_provider), content_type);
}
inline Result Client::Put(const char *path, const Params &params) {
	return cli_->Put(path, params);
}
inline Result Client::Put(const char *path, const Headers &headers,
                          const Params &params) {
	return cli_->Put(path, headers, params);
}
inline Result Client::Patch(const char *path) { return cli_->Patch(path); }
inline Result Client::Patch(const char *path, const char *body,
                            size_t content_length, const char *content_type) {
	return cli_->Patch(path, body, content_length, content_type);
}
inline Result Client::Patch(const char *path, const Headers &headers,
                            const char *body, size_t content_length,
                            const char *content_type) {
	return cli_->Patch(path, headers, body, content_length, content_type);
}
inline Result Client::Patch(const char *path, const std::string &body,
                            const char *content_type) {
	return cli_->Patch(path, body, content_type);
}
inline Result Client::Patch(const char *path, const Headers &headers,
                            const std::string &body, const char *content_type) {
	return cli_->Patch(path, headers, body, content_type);
}
inline Result Client::Patch(const char *path, size_t content_length,
                            ContentProvider content_provider,
                            const char *content_type) {
	return cli_->Patch(path, content_length, std::move(content_provider),
	                   content_type);
}
inline Result Client::Patch(const char *path,
                            ContentProviderWithoutLength content_provider,
                            const char *content_type) {
	return cli_->Patch(path, std::move(content_provider), content_type);
}
inline Result Client::Patch(const char *path, const Headers &headers,
                            size_t content_length,
                            ContentProvider content_provider,
                            const char *content_type) {
	return cli_->Patch(path, headers, content_length, std::move(content_provider),
	                   content_type);
}
inline Result Client::Patch(const char *path, const Headers &headers,
                            ContentProviderWithoutLength content_provider,
                            const char *content_type) {
	return cli_->Patch(path, headers, std::move(content_provider), content_type);
}
inline Result Client::Delete(const char *path) { return cli_->Delete(path); }
inline Result Client::Delete(const char *path, const Headers &headers) {
	return cli_->Delete(path, headers);
}
inline Result Client::Delete(const char *path, const char *body,
                             size_t content_length, const char *content_type) {
	return cli_->Delete(path, body, content_length, content_type);
}
inline Result Client::Delete(const char *path, const Headers &headers,
                             const char *body, size_t content_length,
                             const char *content_type) {
	return cli_->Delete(path, headers, body, content_length, content_type);
}
inline Result Client::Delete(const char *path, const std::string &body,
                             const char *content_type) {
	return cli_->Delete(path, body, content_type);
}
inline Result Client::Delete(const char *path, const Headers &headers,
                             const std::string &body,
                             const char *content_type) {
	return cli_->Delete(path, headers, body, content_type);
}
inline Result Client::Options(const char *path) { return cli_->Options(path); }
inline Result Client::Options(const char *path, const Headers &headers) {
	return cli_->Options(path, headers);
}

inline bool Client::send(Request &req, Response &res, Error &error) {
	return cli_->send(req, res, error);
}

inline Result Client::send(const Request &req) { return cli_->send(req); }

inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }

inline void Client::stop() { cli_->stop(); }

inline void Client::set_hostname_addr_map(
    const std::map<std::string, std::string> addr_map) {
	cli_->set_hostname_addr_map(std::move(addr_map));
}

inline void Client::set_default_headers(Headers headers) {
	cli_->set_default_headers(std::move(headers));
}

inline void Client::set_address_family(int family) {
	cli_->set_address_family(family);
}

inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }

inline void Client::set_socket_options(SocketOptions socket_options) {
	cli_->set_socket_options(std::move(socket_options));
}

inline void Client::set_connection_timeout(time_t sec, time_t usec) {
	cli_->set_connection_timeout(sec, usec);
}

inline void Client::set_read_timeout(time_t sec, time_t usec) {
	cli_->set_read_timeout(sec, usec);
}

inline void Client::set_write_timeout(time_t sec, time_t usec) {
	cli_->set_write_timeout(sec, usec);
}

inline void Client::set_basic_auth(const char *username, const char *password) {
	cli_->set_basic_auth(username, password);
}
inline void Client::set_bearer_token_auth(const char *token) {
	cli_->set_bearer_token_auth(token);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void Client::set_digest_auth(const char *username,
                                    const char *password) {
	cli_->set_digest_auth(username, password);
}
#endif

inline void Client::set_keep_alive(bool on) { cli_->set_keep_alive(on); }
inline void Client::set_follow_location(bool on) {
	cli_->set_follow_location(on);
}

inline void Client::set_url_encode(bool on) { cli_->set_url_encode(on); }

inline void Client::set_compress(bool on) { cli_->set_compress(on); }

inline void Client::set_decompress(bool on) { cli_->set_decompress(on); }

inline void Client::set_interface(const char *intf) {
	cli_->set_interface(intf);
}

inline void Client::set_proxy(const char *host, int port) {
	cli_->set_proxy(host, port);
}
inline void Client::set_proxy_basic_auth(const char *username,
                                         const char *password) {
	cli_->set_proxy_basic_auth(username, password);
}
inline void Client::set_proxy_bearer_token_auth(const char *token) {
	cli_->set_proxy_bearer_token_auth(token);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void Client::set_proxy_digest_auth(const char *username,
                                          const char *password) {
	cli_->set_proxy_digest_auth(username, password);
}
#endif

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void Client::enable_server_certificate_verification(bool enabled) {
	cli_->enable_server_certificate_verification(enabled);
}
#endif

inline void Client::set_logger(Logger logger) { cli_->set_logger(logger); }

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void Client::set_ca_cert_path(const char *ca_cert_file_path,
                                     const char *ca_cert_dir_path) {
	cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path);
}

inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
	if (is_ssl_) {
		static_cast<SSLClient &>(*cli_).set_ca_cert_store(ca_cert_store);
	} else {
		cli_->set_ca_cert_store(ca_cert_store);
	}
}

inline long Client::get_openssl_verify_result() const {
	if (is_ssl_) {
		return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();
	}
	return -1; // NOTE: -1 doesn't match any of X509_V_ERR_???
}

inline SSL_CTX *Client::ssl_context() const {
	if (is_ssl_) { return static_cast<SSLClient &>(*cli_).ssl_context(); }
	return nullptr;
}
#endif

// ----------------------------------------------------------------------------

} // namespace CPPHTTPLIB_NAMESPACE

#endif // CPPHTTPLIB_HTTPLIB_H


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






#ifndef _WIN32
#include <dlfcn.h>
#else
#define RTLD_NOW   0
#define RTLD_LOCAL 0
#endif

namespace duckdb {

#ifdef _WIN32

inline void *dlopen(const char *file, int mode) {
	D_ASSERT(file);
	return (void *)LoadLibrary(file);
}

inline void *dlsym(void *handle, const char *name) {
	D_ASSERT(handle);
	return (void *)GetProcAddress((HINSTANCE)handle, name);
}

inline std::string GetDLError(void) {
	return LocalFileSystem::GetLastErrorAsString();
}

#else

inline std::string GetDLError(void) {
	return dlerror();
}

#endif

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/fstream.hpp
//
//
//===----------------------------------------------------------------------===//



#include <fstream>
#include <iosfwd>

namespace duckdb {
using std::endl;
using std::fstream;
using std::ifstream;
using std::ios;
using std::ios_base;
using std::ofstream;
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/aggregate_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class AggregateRelation : public Relation {
public:
	DUCKDB_API AggregateRelation(shared_ptr<Relation> child, vector<unique_ptr<ParsedExpression>> expressions);
	DUCKDB_API AggregateRelation(shared_ptr<Relation> child, vector<unique_ptr<ParsedExpression>> expressions,
	                             vector<unique_ptr<ParsedExpression>> groups);

	vector<unique_ptr<ParsedExpression>> expressions;
	vector<unique_ptr<ParsedExpression>> groups;
	vector<ColumnDefinition> columns;
	shared_ptr<Relation> child;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/create_table_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class CreateTableRelation : public Relation {
public:
	CreateTableRelation(shared_ptr<Relation> child, string schema_name, string table_name);

	shared_ptr<Relation> child;
	string schema_name;
	string table_name;
	vector<ColumnDefinition> columns;

public:
	BoundStatement Bind(Binder &binder) override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	bool IsReadOnly() override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/create_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class CreateStatement : public SQLStatement {
public:
	CreateStatement();

	unique_ptr<CreateInfo> info;

protected:
	CreateStatement(const CreateStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/create_view_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class CreateViewRelation : public Relation {
public:
	CreateViewRelation(shared_ptr<Relation> child, string view_name, bool replace, bool temporary);

	shared_ptr<Relation> child;
	string view_name;
	bool replace;
	bool temporary;
	vector<ColumnDefinition> columns;

public:
	BoundStatement Bind(Binder &binder) override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	bool IsReadOnly() override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/cross_product_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class CrossProductRelation : public Relation {
public:
	DUCKDB_API CrossProductRelation(shared_ptr<Relation> left, shared_ptr<Relation> right);

	shared_ptr<Relation> left;
	shared_ptr<Relation> right;
	vector<ColumnDefinition> columns;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;

	unique_ptr<TableRef> GetTableRef() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/delete_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class DeleteRelation : public Relation {
public:
	DeleteRelation(ClientContextWrapper &context, unique_ptr<ParsedExpression> condition, string schema_name,
	               string table_name);

	vector<ColumnDefinition> columns;
	unique_ptr<ParsedExpression> condition;
	string schema_name;
	string table_name;

public:
	BoundStatement Bind(Binder &binder) override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	bool IsReadOnly() override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/delete_statement.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class DeleteStatement : public SQLStatement {
public:
	DeleteStatement();

	unique_ptr<ParsedExpression> condition;
	unique_ptr<TableRef> table;
	vector<unique_ptr<TableRef>> using_clauses;
	vector<unique_ptr<ParsedExpression>> returning_list;
	//! CTEs
	CommonTableExpressionMap cte_map;

protected:
	DeleteStatement(const DeleteStatement &other);

public:
	string ToString() const override;
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/distinct_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class DistinctRelation : public Relation {
public:
	explicit DistinctRelation(shared_ptr<Relation> child);

	shared_ptr<Relation> child;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

public:
	bool InheritsColumnBindings() override {
		return true;
	}
	Relation *ChildRelation() override {
		return child.get();
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/explain_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class ExplainRelation : public Relation {
public:
	explicit ExplainRelation(shared_ptr<Relation> child);

	shared_ptr<Relation> child;
	vector<ColumnDefinition> columns;

public:
	BoundStatement Bind(Binder &binder) override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	bool IsReadOnly() override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/filter_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class FilterRelation : public Relation {
public:
	DUCKDB_API FilterRelation(shared_ptr<Relation> child, unique_ptr<ParsedExpression> condition);

	unique_ptr<ParsedExpression> condition;
	shared_ptr<Relation> child;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

public:
	bool InheritsColumnBindings() override {
		return true;
	}
	Relation *ChildRelation() override {
		return child.get();
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/query_node/set_operation_node.hpp
//
//
//===----------------------------------------------------------------------===//



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





namespace duckdb {

enum class SetOperationType : uint8_t { NONE = 0, UNION = 1, EXCEPT = 2, INTERSECT = 3 };
}





namespace duckdb {

class SetOperationNode : public QueryNode {
public:
	SetOperationNode() : QueryNode(QueryNodeType::SET_OPERATION_NODE) {
	}

	//! The type of set operation
	SetOperationType setop_type = SetOperationType::NONE;
	//! The left side of the set operation
	unique_ptr<QueryNode> left;
	//! The right side of the set operation
	unique_ptr<QueryNode> right;

	const vector<unique_ptr<ParsedExpression>> &GetSelectList() const override {
		return left->GetSelectList();
	}

public:
	//! Convert the query node to a string
	string ToString() const override;

	bool Equals(const QueryNode *other) const override;
	//! Create a copy of this SelectNode
	unique_ptr<QueryNode> Copy() const override;

	//! Serializes a QueryNode to a stand-alone binary blob
	void Serialize(FieldWriter &writer) const override;
	//! Deserializes a blob back into a QueryNode
	static unique_ptr<QueryNode> Deserialize(FieldReader &reader);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/insert_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class InsertRelation : public Relation {
public:
	InsertRelation(shared_ptr<Relation> child, string schema_name, string table_name);

	shared_ptr<Relation> child;
	string schema_name;
	string table_name;
	vector<ColumnDefinition> columns;

public:
	BoundStatement Bind(Binder &binder) override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	bool IsReadOnly() override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/insert_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class ExpressionListRef;

class InsertStatement : public SQLStatement {
public:
	InsertStatement();

	//! The select statement to insert from
	unique_ptr<SelectStatement> select_statement;
	//! Column names to insert into
	vector<string> columns;

	//! Table name to insert to
	string table;
	//! Schema name to insert to
	string schema;

	//! keep track of optional returningList if statement contains a RETURNING keyword
	vector<unique_ptr<ParsedExpression>> returning_list;

	//! CTEs
	CommonTableExpressionMap cte_map;

protected:
	InsertStatement(const InsertStatement &other);

public:
	string ToString() const override;
	unique_ptr<SQLStatement> Copy() const override;

	//! If the INSERT statement is inserted DIRECTLY from a values list (i.e. INSERT INTO tbl VALUES (...)) this returns
	//! the expression list Otherwise, this returns NULL
	ExpressionListRef *GetValuesList() const;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/join_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class JoinRelation : public Relation {
public:
	DUCKDB_API JoinRelation(shared_ptr<Relation> left, shared_ptr<Relation> right,
	                        unique_ptr<ParsedExpression> condition, JoinType type);
	DUCKDB_API JoinRelation(shared_ptr<Relation> left, shared_ptr<Relation> right, vector<string> using_columns,
	                        JoinType type);

	shared_ptr<Relation> left;
	shared_ptr<Relation> right;
	unique_ptr<ParsedExpression> condition;
	vector<string> using_columns;
	JoinType join_type;
	vector<ColumnDefinition> columns;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;

	unique_ptr<TableRef> GetTableRef() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/limit_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class LimitRelation : public Relation {
public:
	DUCKDB_API LimitRelation(shared_ptr<Relation> child, int64_t limit, int64_t offset);

	int64_t limit;
	int64_t offset;
	shared_ptr<Relation> child;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

public:
	bool InheritsColumnBindings() override {
		return true;
	}
	Relation *ChildRelation() override {
		return child.get();
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/order_relation.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class OrderRelation : public Relation {
public:
	DUCKDB_API OrderRelation(shared_ptr<Relation> child, vector<OrderByNode> orders);

	vector<OrderByNode> orders;
	shared_ptr<Relation> child;
	vector<ColumnDefinition> columns;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

public:
	bool InheritsColumnBindings() override {
		return true;
	}
	Relation *ChildRelation() override {
		return child.get();
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/projection_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class ProjectionRelation : public Relation {
public:
	DUCKDB_API ProjectionRelation(shared_ptr<Relation> child, vector<unique_ptr<ParsedExpression>> expressions,
	                              vector<string> aliases);

	vector<unique_ptr<ParsedExpression>> expressions;
	vector<ColumnDefinition> columns;
	shared_ptr<Relation> child;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/setop_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class SetOpRelation : public Relation {
public:
	SetOpRelation(shared_ptr<Relation> left, shared_ptr<Relation> right, SetOperationType setop_type);

	shared_ptr<Relation> left;
	shared_ptr<Relation> right;
	SetOperationType setop_type;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/subquery_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class SubqueryRelation : public Relation {
public:
	SubqueryRelation(shared_ptr<Relation> child, string alias);

	shared_ptr<Relation> child;
	string alias;

public:
	unique_ptr<QueryNode> GetQueryNode() override;

	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	string GetAlias() override;

public:
	bool InheritsColumnBindings() override {
		return child->InheritsColumnBindings();
	}
	Relation *ChildRelation() override {
		return child->ChildRelation();
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/update_relation.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class UpdateRelation : public Relation {
public:
	UpdateRelation(ClientContextWrapper &context, unique_ptr<ParsedExpression> condition, string schema_name,
	               string table_name, vector<string> update_columns, vector<unique_ptr<ParsedExpression>> expressions);

	vector<ColumnDefinition> columns;
	unique_ptr<ParsedExpression> condition;
	string schema_name;
	string table_name;
	vector<string> update_columns;
	vector<unique_ptr<ParsedExpression>> expressions;

public:
	BoundStatement Bind(Binder &binder) override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	bool IsReadOnly() override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/update_statement.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

class UpdateStatement : public SQLStatement {
public:
	UpdateStatement();

	unique_ptr<ParsedExpression> condition;
	unique_ptr<TableRef> table;
	unique_ptr<TableRef> from_table;
	vector<string> columns;
	vector<unique_ptr<ParsedExpression>> expressions;
	//! keep track of optional returningList if statement contains a RETURNING keyword
	vector<unique_ptr<ParsedExpression>> returning_list;
	//! CTEs
	CommonTableExpressionMap cte_map;

protected:
	UpdateStatement(const UpdateStatement &other);

public:
	string ToString() const override;
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/main/relation/write_csv_relation.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class WriteCSVRelation : public Relation {
public:
	WriteCSVRelation(shared_ptr<Relation> child, string csv_file);

	shared_ptr<Relation> child;
	string csv_file;
	vector<ColumnDefinition> columns;

public:
	BoundStatement Bind(Binder &binder) override;
	const vector<ColumnDefinition> &Columns() override;
	string ToString(idx_t depth) override;
	bool IsReadOnly() override {
		return false;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/copy_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class CopyStatement : public SQLStatement {
public:
	CopyStatement();

	unique_ptr<CopyInfo> info;
	// The SQL statement used instead of a table when copying data out to a file
	unique_ptr<QueryNode> select_statement;

protected:
	CopyStatement(const CopyStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/column_lifetime_optimizer.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class BoundColumnRefExpression;

//! The ColumnLifetimeAnalyzer optimizer traverses the logical operator tree and ensures that columns are removed from
//! the plan when no longer required
class ColumnLifetimeAnalyzer : public LogicalOperatorVisitor {
public:
	explicit ColumnLifetimeAnalyzer(bool is_root = false) : everything_referenced(is_root) {
	}

	void VisitOperator(LogicalOperator &op) override;

protected:
	unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr) override;
	unique_ptr<Expression> VisitReplace(BoundReferenceExpression &expr, unique_ptr<Expression> *expr_ptr) override;

private:
	//! Whether or not all the columns are referenced. This happens in the case of the root expression (because the
	//! output implicitly refers all the columns below it)
	bool everything_referenced;
	//! The set of column references
	column_binding_set_t column_references;

private:
	void StandardVisitOperator(LogicalOperator &op);

	void ExtractUnusedColumnBindings(vector<ColumnBinding> bindings, column_binding_set_t &unused_bindings);
	void GenerateProjectionMap(vector<ColumnBinding> bindings, column_binding_set_t &unused_bindings,
	                           vector<idx_t> &map);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/common_aggregate_optimizer.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
//! The CommonAggregateOptimizer optimizer eliminates duplicate aggregates from aggregate nodes
class CommonAggregateOptimizer : public LogicalOperatorVisitor {
public:
	void VisitOperator(LogicalOperator &op) override;

private:
	unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr) override;

	void ExtractCommonAggregates(LogicalAggregate &aggr);

private:
	column_binding_map_t<ColumnBinding> aggregate_map;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/expression_map.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Expression;

struct ExpressionHashFunction {
	uint64_t operator()(const BaseExpression *const &expr) const {
		return (uint64_t)expr->Hash();
	}
};

struct ExpressionEquality {
	bool operator()(const BaseExpression *const &a, const BaseExpression *const &b) const {
		return a->Equals(b);
	}
};

template <typename T>
using expression_map_t = unordered_map<BaseExpression *, T, ExpressionHashFunction, ExpressionEquality>;

using expression_set_t = unordered_set<BaseExpression *, ExpressionHashFunction, ExpressionEquality>;

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/cse_optimizer.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Binder;
struct CSEReplacementState;

//! The CommonSubExpression optimizer traverses the expressions of a LogicalOperator to look for duplicate expressions
//! if there are any, it pushes a projection under the operator that resolves these expressions
class CommonSubExpressionOptimizer : public LogicalOperatorVisitor {
public:
	explicit CommonSubExpressionOptimizer(Binder &binder) : binder(binder) {
	}

public:
	void VisitOperator(LogicalOperator &op) override;

private:
	//! First iteration: count how many times each expression occurs
	void CountExpressions(Expression &expr, CSEReplacementState &state);
	//! Second iteration: perform the actual replacement of the duplicate expressions with common subexpressions nodes
	void PerformCSEReplacement(unique_ptr<Expression> *expr, CSEReplacementState &state);

	//! Main method to extract common subexpressions
	void ExtractCommonSubExpresions(LogicalOperator &op);

private:
	Binder &binder;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/deliminator.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class Optimizer;
class DeliminatorPlanUpdater;

//! The Deliminator optimizer traverses the logical operator tree and removes any redundant DelimGets/DelimJoins
class Deliminator {
public:
	Deliminator() {
	}
	//! Perform DelimJoin elimination
	unique_ptr<LogicalOperator> Optimize(unique_ptr<LogicalOperator> op);

private:
	//! Find Joins with a DelimGet that can be removed
	void FindCandidates(unique_ptr<LogicalOperator> *op_ptr, vector<unique_ptr<LogicalOperator> *> &candidates);
	//! Try to remove a Join with a DelimGet, returns true if it was successful
	bool RemoveCandidate(unique_ptr<LogicalOperator> *op_ptr, DeliminatorPlanUpdater &updater);
	//! Replace references to a removed DelimGet, remove DelimJoins if all their DelimGets are gone
	void UpdatePlan(LogicalOperator &op, expression_map_t<Expression *> &expr_map,
	                column_binding_map_t<bool> &projection_map);
	//! Whether the operator has one or more children of type DELIM_GET
	bool HasChildDelimGet(LogicalOperator &op);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/expression_heuristics.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class ExpressionHeuristics : public LogicalOperatorVisitor {
public:
	explicit ExpressionHeuristics(Optimizer &optimizer) : optimizer(optimizer) {
	}

	Optimizer &optimizer;
	unique_ptr<LogicalOperator> root;

public:
	//! Search for filters to be reordered
	unique_ptr<LogicalOperator> Rewrite(unique_ptr<LogicalOperator> op);
	//! Reorder the expressions of a filter
	void ReorderExpressions(vector<unique_ptr<Expression>> &expressions);
	//! Return the cost of an expression
	idx_t Cost(Expression &expr);

	unique_ptr<Expression> VisitReplace(BoundConjunctionExpression &expr, unique_ptr<Expression> *expr_ptr) override;
	//! Override this function to search for filter operators
	void VisitOperator(LogicalOperator &op) override;

private:
	unordered_map<std::string, idx_t> function_costs = {
	    {"+", 5},       {"-", 5},    {"&", 5},          {"#", 5},
	    {">>", 5},      {"<<", 5},   {"abs", 5},        {"*", 10},
	    {"%", 10},      {"/", 15},   {"date_part", 20}, {"year", 20},
	    {"round", 100}, {"~~", 200}, {"!~~", 200},      {"regexp_matches", 200},
	    {"||", 200}};

	idx_t ExpressionCost(BoundBetweenExpression &expr);
	idx_t ExpressionCost(BoundCaseExpression &expr);
	idx_t ExpressionCost(BoundCastExpression &expr);
	idx_t ExpressionCost(BoundComparisonExpression &expr);
	idx_t ExpressionCost(BoundConjunctionExpression &expr);
	idx_t ExpressionCost(BoundFunctionExpression &expr);
	idx_t ExpressionCost(BoundOperatorExpression &expr, ExpressionType &expr_type);
	idx_t ExpressionCost(PhysicalType return_type, idx_t multiplier);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/filter_combiner.hpp
//
//
//===----------------------------------------------------------------------===//











#include <functional>
#include <map>

namespace duckdb {

enum class ValueComparisonResult { PRUNE_LEFT, PRUNE_RIGHT, UNSATISFIABLE_CONDITION, PRUNE_NOTHING };
enum class FilterResult { UNSATISFIABLE, SUCCESS, UNSUPPORTED };

//! The FilterCombiner combines several filters and generates a logically equivalent set that is more efficient
//! Amongst others:
//! (1) it prunes obsolete filter conditions: i.e. [X > 5 and X > 7] => [X > 7]
//! (2) it generates new filters for expressions in the same equivalence set: i.e. [X = Y and X = 500] => [Y = 500]
//! (3) it prunes branches that have unsatisfiable filters: i.e. [X = 5 AND X > 6] => FALSE, prune branch
class FilterCombiner {
public:
	struct ExpressionValueInformation {
		Value constant;
		ExpressionType comparison_type;
	};

	FilterResult AddFilter(unique_ptr<Expression> expr);

	void GenerateFilters(const std::function<void(unique_ptr<Expression> filter)> &callback);
	bool HasFilters();
	TableFilterSet GenerateTableScanFilters(vector<idx_t> &column_ids);
	// vector<unique_ptr<TableFilter>> GenerateZonemapChecks(vector<idx_t> &column_ids, vector<unique_ptr<TableFilter>>
	// &pushed_filters);

private:
	FilterResult AddFilter(Expression *expr);
	FilterResult AddBoundComparisonFilter(Expression *expr);
	FilterResult AddTransitiveFilters(BoundComparisonExpression &comparison);
	unique_ptr<Expression> FindTransitiveFilter(Expression *expr);
	// unordered_map<idx_t, std::pair<Value *, Value *>>
	// FindZonemapChecks(vector<idx_t> &column_ids, unordered_set<idx_t> &not_constants, Expression *filter);
	Expression *GetNode(Expression *expr);
	idx_t GetEquivalenceSet(Expression *expr);
	FilterResult AddConstantComparison(vector<ExpressionValueInformation> &info_list, ExpressionValueInformation info);
	//
	//	//! Functions used to push and generate OR Filters
	//	void LookUpConjunctions(Expression *expr);
	//	bool BFSLookUpConjunctions(BoundConjunctionExpression *conjunction);
	//	void VerifyOrsToPush(Expression &expr);
	//
	//	bool UpdateConjunctionFilter(BoundComparisonExpression *comparison_expr);
	//	bool UpdateFilterByColumn(BoundColumnRefExpression *column_ref, BoundComparisonExpression *comparison_expr);
	//	void GenerateORFilters(TableFilterSet &table_filter, vector<idx_t> &column_ids);
	//
	//	template <typename CONJUNCTION_TYPE>
	//	void GenerateConjunctionFilter(BoundConjunctionExpression *conjunction, ConjunctionFilter *last_conj_filter) {
	//		auto new_filter = NextConjunctionFilter<CONJUNCTION_TYPE>(conjunction);
	//		auto conj_filter_ptr = (ConjunctionFilter *)new_filter.get();
	//		last_conj_filter->child_filters.push_back(move(new_filter));
	//		last_conj_filter = conj_filter_ptr;
	//	}
	//
	//	template <typename CONJUNCTION_TYPE>
	//	unique_ptr<TableFilter> NextConjunctionFilter(BoundConjunctionExpression *conjunction) {
	//		unique_ptr<ConjunctionFilter> conj_filter = make_unique<CONJUNCTION_TYPE>();
	//		for (auto &expr : conjunction->children) {
	//			auto comp_expr = (BoundComparisonExpression *)expr.get();
	//			auto &const_expr =
	//			    (comp_expr->left->type == ExpressionType::VALUE_CONSTANT) ? *comp_expr->left : *comp_expr->right;
	//			auto const_value = ExpressionExecutor::EvaluateScalar(const_expr);
	//			auto const_filter = make_unique<ConstantFilter>(comp_expr->type, const_value);
	//			conj_filter->child_filters.push_back(move(const_filter));
	//		}
	//		return move(conj_filter);
	//	}

private:
	vector<unique_ptr<Expression>> remaining_filters;

	expression_map_t<unique_ptr<Expression>> stored_expressions;
	unordered_map<Expression *, idx_t> equivalence_set_map;
	unordered_map<idx_t, vector<ExpressionValueInformation>> constant_values;
	unordered_map<idx_t, vector<Expression *>> equivalence_map;
	idx_t set_index = 0;
	//
	//	//! Structures used for OR Filters
	//
	//	struct ConjunctionsToPush {
	//		BoundConjunctionExpression *root_or;
	//
	//		// only preserve AND if there is a single column in the expression
	//		bool preserve_and = true;
	//
	//		// conjunction chain for this column
	//		vector<unique_ptr<BoundConjunctionExpression>> conjunctions;
	//	};
	//
	//	expression_map_t<vector<unique_ptr<ConjunctionsToPush>>> map_col_conjunctions;
	//	vector<BoundColumnRefExpression *> vec_colref_insertion_order;
	//
	//	BoundConjunctionExpression *cur_root_or;
	//	BoundConjunctionExpression *cur_conjunction;
	//
	//	BoundColumnRefExpression *cur_colref_to_push;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/filter_pullup.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {

class FilterPullup {
public:
	explicit FilterPullup(bool pullup = false, bool add_column = false)
	    : can_pullup(pullup), can_add_column(add_column) {
	}

	//! Perform filter pullup
	unique_ptr<LogicalOperator> Rewrite(unique_ptr<LogicalOperator> op);

private:
	vector<unique_ptr<Expression>> filters_expr_pullup;

	// only pull up filters when there is a fork
	bool can_pullup = false;

	// identifiy case the branch is a set operation (INTERSECT or EXCEPT)
	bool can_add_column = false;

private:
	// Generate logical filters pulled up
	unique_ptr<LogicalOperator> GeneratePullupFilter(unique_ptr<LogicalOperator> child,
	                                                 vector<unique_ptr<Expression>> &expressions);

	//! Pull up a LogicalFilter op
	unique_ptr<LogicalOperator> PullupFilter(unique_ptr<LogicalOperator> op);

	//! Pull up filter in a LogicalProjection op
	unique_ptr<LogicalOperator> PullupProjection(unique_ptr<LogicalOperator> op);

	//! Pull up filter in a LogicalCrossProduct op
	unique_ptr<LogicalOperator> PullupCrossProduct(unique_ptr<LogicalOperator> op);

	unique_ptr<LogicalOperator> PullupJoin(unique_ptr<LogicalOperator> op);

	// PPullup filter in a left join
	unique_ptr<LogicalOperator> PullupFromLeft(unique_ptr<LogicalOperator> op);

	// Pullup filter in a inner join
	unique_ptr<LogicalOperator> PullupInnerJoin(unique_ptr<LogicalOperator> op);

	// Pullup filter in LogicalIntersect or LogicalExcept op
	unique_ptr<LogicalOperator> PullupSetOperation(unique_ptr<LogicalOperator> op);

	unique_ptr<LogicalOperator> PullupBothSide(unique_ptr<LogicalOperator> op);

	// Finish pull up at this operator
	unique_ptr<LogicalOperator> FinishPullup(unique_ptr<LogicalOperator> op);

	// special treatment for SetOperations and projections
	void ProjectSetOperation(LogicalProjection &proj);

}; // end FilterPullup

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/filter_pushdown.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class Optimizer;

class FilterPushdown {
public:
	explicit FilterPushdown(Optimizer &optimizer) : optimizer(optimizer) {
	}
	//! Perform filter pushdown
	unique_ptr<LogicalOperator> Rewrite(unique_ptr<LogicalOperator> op);

	struct Filter {
		unordered_set<idx_t> bindings;
		unique_ptr<Expression> filter;

		Filter() {
		}
		explicit Filter(unique_ptr<Expression> filter) : filter(move(filter)) {
		}

		void ExtractBindings();
	};

private:
	vector<unique_ptr<Filter>> filters;
	Optimizer &optimizer;

	//! Push down a LogicalAggregate op
	unique_ptr<LogicalOperator> PushdownAggregate(unique_ptr<LogicalOperator> op);
	//! Push down a LogicalFilter op
	unique_ptr<LogicalOperator> PushdownFilter(unique_ptr<LogicalOperator> op);
	//! Push down a LogicalCrossProduct op
	unique_ptr<LogicalOperator> PushdownCrossProduct(unique_ptr<LogicalOperator> op);
	//! Push down a join operator
	unique_ptr<LogicalOperator> PushdownJoin(unique_ptr<LogicalOperator> op);
	//! Push down a LogicalProjection op
	unique_ptr<LogicalOperator> PushdownProjection(unique_ptr<LogicalOperator> op);
	//! Push down a LogicalSetOperation op
	unique_ptr<LogicalOperator> PushdownSetOperation(unique_ptr<LogicalOperator> op);
	//! Push down a LogicalGet op
	unique_ptr<LogicalOperator> PushdownGet(unique_ptr<LogicalOperator> op);
	//! Push down a LogicalLimit op
	unique_ptr<LogicalOperator> PushdownLimit(unique_ptr<LogicalOperator> op);
	// Pushdown an inner join
	unique_ptr<LogicalOperator> PushdownInnerJoin(unique_ptr<LogicalOperator> op, unordered_set<idx_t> &left_bindings,
	                                              unordered_set<idx_t> &right_bindings);
	// Pushdown a left join
	unique_ptr<LogicalOperator> PushdownLeftJoin(unique_ptr<LogicalOperator> op, unordered_set<idx_t> &left_bindings,
	                                             unordered_set<idx_t> &right_bindings);
	// Pushdown a mark join
	unique_ptr<LogicalOperator> PushdownMarkJoin(unique_ptr<LogicalOperator> op, unordered_set<idx_t> &left_bindings,
	                                             unordered_set<idx_t> &right_bindings);
	// Pushdown a single join
	unique_ptr<LogicalOperator> PushdownSingleJoin(unique_ptr<LogicalOperator> op, unordered_set<idx_t> &left_bindings,
	                                               unordered_set<idx_t> &right_bindings);

	// Finish pushing down at this operator, creating a LogicalFilter to store any of the stored filters and recursively
	// pushing down into its children (if any)
	unique_ptr<LogicalOperator> FinishPushdown(unique_ptr<LogicalOperator> op);
	//! Adds a filter to the set of filters. Returns FilterResult::UNSATISFIABLE if the subtree should be stripped, or
	//! FilterResult::SUCCESS otherwise
	FilterResult AddFilter(unique_ptr<Expression> expr);
	//! Generate filters from the current set of filters stored in the FilterCombiner
	void GenerateFilters();
	//! if there are filters in this FilterPushdown node, push them into the combiner
	void PushFilters();

	FilterCombiner combiner;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/in_clause_rewriter.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class ClientContext;
class Optimizer;

class InClauseRewriter : public LogicalOperatorVisitor {
public:
	explicit InClauseRewriter(ClientContext &context, Optimizer &optimizer) : context(context), optimizer(optimizer) {
	}

	ClientContext &context;
	Optimizer &optimizer;
	unique_ptr<LogicalOperator> root;

public:
	unique_ptr<LogicalOperator> Rewrite(unique_ptr<LogicalOperator> op);

	unique_ptr<Expression> VisitReplace(BoundOperatorExpression &expr, unique_ptr<Expression> *expr_ptr) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/join_relation.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class LogicalOperator;

//! Represents a single relation and any metadata accompanying that relation
struct SingleJoinRelation {
	LogicalOperator *op;
	LogicalOperator *parent;

	SingleJoinRelation() {
	}
	SingleJoinRelation(LogicalOperator *op, LogicalOperator *parent) : op(op), parent(parent) {
	}
};

//! Set of relations, used in the join graph.
struct JoinRelationSet {
	JoinRelationSet(unique_ptr<idx_t[]> relations, idx_t count) : relations(move(relations)), count(count) {
	}

	string ToString() const;

	unique_ptr<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(unordered_set<idx_t> &bindings);
	//! Create or get a JoinRelationSet from a (sorted, duplicate-free!) list of relations
	JoinRelationSet *GetJoinRelation(unique_ptr<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);

private:
	JoinRelationTreeNode root;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order/query_graph.hpp
//
//
//===----------------------------------------------------------------------===//









#include <functional>

namespace duckdb {
class Expression;
class LogicalOperator;

struct FilterInfo {
	idx_t filter_index;
	JoinRelationSet *left_set = nullptr;
	JoinRelationSet *right_set = nullptr;
	JoinRelationSet *set = nullptr;
};

struct FilterNode {
	vector<FilterInfo *> filters;
	unordered_map<idx_t, unique_ptr<FilterNode>> children;
};

struct NeighborInfo {
	JoinRelationSet *neighbor;
	vector<FilterInfo *> filters;
};

//! The QueryGraph contains edges between relations and allows edges to be created/queried
class QueryGraph {
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();

	//! Create an edge in the edge_set
	void CreateEdge(JoinRelationSet *left, JoinRelationSet *right, FilterInfo *info);
	//! Returns a connection if there is an edge that connects these two sets, or nullptr otherwise
	NeighborInfo *GetConnection(JoinRelationSet *node, JoinRelationSet *other);
	//! 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.
	vector<idx_t> GetNeighbors(JoinRelationSet *node, unordered_set<idx_t> &exclusion_set);
	//! Enumerate all neighbors of a given JoinRelationSet node
	void EnumerateNeighbors(JoinRelationSet *node, const std::function<bool(NeighborInfo *)> &callback);

private:
	//! Get the QueryEdge of a specific node
	QueryEdge *GetQueryEdge(JoinRelationSet *left);

	QueryEdge root;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/join_order_optimizer.hpp
//
//
//===----------------------------------------------------------------------===//











#include <functional>

namespace duckdb {

class JoinOrderOptimizer {
public:
	//! Represents a node in the join plan
	struct JoinNode {
		JoinRelationSet *set;
		NeighborInfo *info;
		idx_t cardinality;
		idx_t cost;
		JoinNode *left;
		JoinNode *right;

		//! Create a leaf node in the join tree
		JoinNode(JoinRelationSet *set, idx_t cardinality)
		    : set(set), info(nullptr), cardinality(cardinality), cost(cardinality), left(nullptr), right(nullptr) {
		}
		//! Create an intermediate node in the join tree
		JoinNode(JoinRelationSet *set, NeighborInfo *info, JoinNode *left, JoinNode *right, idx_t cardinality,
		         idx_t cost)
		    : set(set), info(info), cardinality(cardinality), cost(cost), left(left), right(right) {
		}
	};

public:
	explicit JoinOrderOptimizer(ClientContext &context) : context(context) {
	}

	//! Perform join reordering inside a plan
	unique_ptr<LogicalOperator> Optimize(unique_ptr<LogicalOperator> plan);

private:
	ClientContext &context;
	//! The total amount of join pairs that have been considered
	idx_t pairs = 0;
	//! Set of all relations considered in the join optimizer
	vector<unique_ptr<SingleJoinRelation>> relations;
	//! A mapping of base table index -> index into relations array (relation number)
	unordered_map<idx_t, idx_t> relation_mapping;
	//! A structure holding all the created JoinRelationSet objects
	JoinRelationSetManager set_manager;
	//! The set of edges used in the join optimizer
	QueryGraph query_graph;
	//! The optimal join plan found for the specific JoinRelationSet*
	unordered_map<JoinRelationSet *, unique_ptr<JoinNode>> plans;
	//! The set of filters extracted from the query graph
	vector<unique_ptr<Expression>> filters;
	//! The set of filter infos created from the extracted filters
	vector<unique_ptr<FilterInfo>> filter_infos;
	//! A map of all expressions a given expression has to be equivalent to. This is used to add "implied join edges".
	//! i.e. in the join A=B AND B=C, the equivalence set of {B} is {A, C}, thus we can add an implied join edge {A <->
	//! C}
	expression_map_t<vector<FilterInfo *>> equivalence_sets;

	//! Extract the bindings referred to by an Expression
	bool ExtractBindings(Expression &expression, unordered_set<idx_t> &bindings);
	//! Traverse the query tree to find (1) base relations, (2) existing join conditions and (3) filters that can be
	//! rewritten into joins. Returns true if there are joins in the tree that can be reordered, false otherwise.
	bool ExtractJoinRelations(LogicalOperator &input_op, vector<LogicalOperator *> &filter_operators,
	                          LogicalOperator *parent = nullptr);
	//! Emit a pair as a potential join candidate. Returns the best plan found for the (left, right) connection (either
	//! the newly created plan, or an existing plan)
	JoinNode *EmitPair(JoinRelationSet *left, JoinRelationSet *right, NeighborInfo *info);
	//! Tries to emit a potential join candidate pair. Returns false if too many pairs have already been emitted,
	//! cancelling the dynamic programming step.
	bool TryEmitPair(JoinRelationSet *left, JoinRelationSet *right, NeighborInfo *info);

	bool EnumerateCmpRecursive(JoinRelationSet *left, JoinRelationSet *right, unordered_set<idx_t> exclusion_set);
	//! Emit a relation set node
	bool EmitCSG(JoinRelationSet *node);
	//! Enumerate the possible connected subgraphs that can be joined together in the join graph
	bool EnumerateCSGRecursive(JoinRelationSet *node, unordered_set<idx_t> &exclusion_set);
	//! Rewrite a logical query plan given the join plan
	unique_ptr<LogicalOperator> RewritePlan(unique_ptr<LogicalOperator> plan, JoinNode *node);
	//! Generate cross product edges inside the side
	void GenerateCrossProducts();
	//! Perform the join order solving
	void SolveJoinOrder();
	//! Solve the join order exactly using dynamic programming. Returns true if it was completed successfully (i.e. did
	//! not time-out)
	bool SolveJoinOrderExactly();
	//! Solve the join order approximately using a greedy algorithm
	void SolveJoinOrderApproximately();

	unique_ptr<LogicalOperator> ResolveJoinConditions(unique_ptr<LogicalOperator> op);
	std::pair<JoinRelationSet *, unique_ptr<LogicalOperator>>
	GenerateJoins(vector<unique_ptr<LogicalOperator>> &extracted_relations, JoinNode *node);
};

} // namespace duckdb








































//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/regex_range_filter.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class Optimizer;

class RegexRangeFilter {
public:
	RegexRangeFilter() {
	}
	//! Perform filter pushdown
	unique_ptr<LogicalOperator> Rewrite(unique_ptr<LogicalOperator> op);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/remove_unused_columns.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Binder;
class BoundColumnRefExpression;
class ClientContext;

//! The RemoveUnusedColumns optimizer traverses the logical operator tree and removes any columns that are not required
class RemoveUnusedColumns : public LogicalOperatorVisitor {
public:
	RemoveUnusedColumns(Binder &binder, ClientContext &context, bool is_root = false)
	    : binder(binder), context(context), everything_referenced(is_root) {
	}

	void VisitOperator(LogicalOperator &op) override;

protected:
	unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr) override;
	unique_ptr<Expression> VisitReplace(BoundReferenceExpression &expr, unique_ptr<Expression> *expr_ptr) override;

private:
	Binder &binder;
	ClientContext &context;
	//! Whether or not all the columns are referenced. This happens in the case of the root expression (because the
	//! output implicitly refers all the columns below it)
	bool everything_referenced;
	//! The map of column references
	column_binding_map_t<vector<BoundColumnRefExpression *>> column_references;

private:
	template <class T>
	void ClearUnusedExpressions(vector<T> &list, idx_t table_idx);

	//! Perform a replacement of the ColumnBinding, iterating over all the currently found column references and
	//! replacing the bindings
	void ReplaceBinding(ColumnBinding current_binding, ColumnBinding new_binding);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/arithmetic_simplification.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The Arithmetic Simplification rule applies arithmetic expressions to which the answer is known (e.g. X + 0 => X, X *
// 0 => 0)
class ArithmeticSimplificationRule : public Rule {
public:
	explicit ArithmeticSimplificationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/case_simplification.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The Case Simplification rule rewrites cases with a constant check (i.e. [CASE WHEN 1=1 THEN x ELSE y END] => x)
class CaseSimplificationRule : public Rule {
public:
	explicit CaseSimplificationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/comparison_simplification.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The Comparison Simplification rule rewrites comparisons with a constant NULL (i.e. [x = NULL] => [NULL])
class ComparisonSimplificationRule : public Rule {
public:
	explicit ComparisonSimplificationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/conjunction_simplification.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The Conjunction Simplification rule rewrites conjunctions with a constant
class ConjunctionSimplificationRule : public Rule {
public:
	explicit ConjunctionSimplificationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;

	unique_ptr<Expression> RemoveExpression(BoundConjunctionExpression &conj, Expression *expr);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/constant_folding.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// Fold any constant scalar expressions into a single constant (i.e. [2 + 2] => [4], [2 = 2] => [True], etc...)
class ConstantFoldingRule : public Rule {
public:
	explicit ConstantFoldingRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/date_part_simplification.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The DatePart Simplification rule rewrites date_part with a constant specifier into a specialized function (e.g.
// date_part('year', x) => year(x))
class DatePartSimplificationRule : public Rule {
public:
	explicit DatePartSimplificationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/distributivity.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

// (X AND B) OR (X AND C) OR (X AND D) = X AND (B OR C OR D)
class DistributivityRule : public Rule {
public:
	explicit DistributivityRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;

private:
	void AddExpressionSet(Expression &expr, expression_set_t &set);
	unique_ptr<Expression> ExtractExpression(BoundConjunctionExpression &conj, idx_t idx, Expression &expr);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/empty_needle_removal.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The Empty_needle_removal Optimization rule folds some foldable ConstantExpression
//(e.g.: PREFIX('xyz', '') is TRUE, PREFIX(NULL, '') is NULL, so rewrite PREFIX(x, '') to (CASE WHEN x IS NOT NULL THEN)
class EmptyNeedleRemovalRule : public Rule {
public:
	explicit EmptyNeedleRemovalRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/like_optimizations.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

// The Like Optimization rule rewrites LIKE to optimized scalar functions (e.g.: prefix, suffix, and contains)
class LikeOptimizationRule : public Rule {
public:
	explicit LikeOptimizationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;

	unique_ptr<Expression> ApplyRule(BoundFunctionExpression *expr, ScalarFunction function, string pattern,
	                                 bool is_not_like);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/move_constants.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The MoveConstantsRule moves constants to the same side of an expression, e.g. if we have an expression x + 1 = 5000
// then this will turn it into x = 4999.
class MoveConstantsRule : public Rule {
public:
	explicit MoveConstantsRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/enum_comparison.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The Enum Comparison rule rewrites cases where two Enums are compared on an equality check
class EnumComparisonRule : public Rule {
public:
	explicit EnumComparisonRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/like_optimizations.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class RegexOptimizationRule : public Rule {
public:
	explicit RegexOptimizationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;

	unique_ptr<Expression> ApplyRule(BoundFunctionExpression *expr, ScalarFunction function, string pattern,
	                                 bool is_not_like);
};

} // namespace duckdb

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/statistics_propagator.hpp
//
//
//===----------------------------------------------------------------------===//












namespace duckdb {
class ClientContext;
class LogicalOperator;
class TableFilter;
struct BoundOrderByNode;

class StatisticsPropagator {
public:
	explicit StatisticsPropagator(ClientContext &context);

	unique_ptr<NodeStatistics> PropagateStatistics(unique_ptr<LogicalOperator> &node_ptr);

private:
	//! Propagate statistics through an operator
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalOperator &node, unique_ptr<LogicalOperator> *node_ptr);

	unique_ptr<NodeStatistics> PropagateStatistics(LogicalFilter &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalGet &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalJoin &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalProjection &op, unique_ptr<LogicalOperator> *node_ptr);
	void PropagateStatistics(LogicalComparisonJoin &op, unique_ptr<LogicalOperator> *node_ptr);
	void PropagateStatistics(LogicalAnyJoin &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalSetOperation &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalAggregate &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalCrossProduct &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalLimit &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalOrder &op, unique_ptr<LogicalOperator> *node_ptr);
	unique_ptr<NodeStatistics> PropagateStatistics(LogicalWindow &op, unique_ptr<LogicalOperator> *node_ptr);

	unique_ptr<NodeStatistics> PropagateChildren(LogicalOperator &node, unique_ptr<LogicalOperator> *node_ptr);

	//! Return statistics from a constant value
	unique_ptr<BaseStatistics> StatisticsFromValue(const Value &input);
	//! Run a comparison with two sets of statistics, returns if the comparison will always returns true/false or not
	FilterPropagateResult PropagateComparison(BaseStatistics &left, BaseStatistics &right, ExpressionType comparison);

	//! Update filter statistics from a filter with a constant
	void UpdateFilterStatistics(BaseStatistics &input, ExpressionType comparison_type, const Value &constant);
	//! Update statistics from a filter between two stats
	void UpdateFilterStatistics(BaseStatistics &lstats, BaseStatistics &rstats, ExpressionType comparison_type);
	//! Update filter statistics from a generic comparison
	void UpdateFilterStatistics(Expression &left, Expression &right, ExpressionType comparison_type);
	//! Update filter statistics from an expression
	void UpdateFilterStatistics(Expression &condition);
	//! Set the statistics of a specific column binding to not contain null values
	void SetStatisticsNotNull(ColumnBinding binding);

	//! Run a comparison between the statistics and the table filter; returns the prune result
	FilterPropagateResult PropagateTableFilter(BaseStatistics &stats, TableFilter &filter);
	//! Update filter statistics from a TableFilter
	void UpdateFilterStatistics(BaseStatistics &input, TableFilter &filter);

	//! Add cardinalities together (i.e. new max is stats.max + new_stats.max): used for union
	void AddCardinalities(unique_ptr<NodeStatistics> &stats, NodeStatistics &new_stats);
	//! Multiply the cardinalities together (i.e. new max cardinality is stats.max * new_stats.max): used for
	//! joins/cross products
	void MultiplyCardinalities(unique_ptr<NodeStatistics> &stats, NodeStatistics &new_stats);

	unique_ptr<BaseStatistics> PropagateExpression(unique_ptr<Expression> &expr);
	unique_ptr<BaseStatistics> PropagateExpression(Expression &expr, unique_ptr<Expression> *expr_ptr);

	unique_ptr<BaseStatistics> PropagateExpression(BoundAggregateExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundBetweenExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundCaseExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundCastExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundConjunctionExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundFunctionExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundComparisonExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundConstantExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr);
	unique_ptr<BaseStatistics> PropagateExpression(BoundOperatorExpression &expr, unique_ptr<Expression> *expr_ptr);

	void PropagateAndCompress(unique_ptr<Expression> &expr, unique_ptr<BaseStatistics> &stats);

	void ReplaceWithEmptyResult(unique_ptr<LogicalOperator> &node);

	bool ExpressionIsConstant(Expression &expr, const Value &val);
	bool ExpressionIsConstantOrNull(Expression &expr, const Value &val);

private:
	ClientContext &context;
	//! The map of ColumnBinding -> statistics for the various nodes
	column_binding_map_t<unique_ptr<BaseStatistics>> statistics_map;
	//! Node stats for the current node
	unique_ptr<NodeStatistics> node_stats;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/topn_optimizer.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class LogicalOperator;
class Optimizer;

class TopN {
public:
	//! Optimize ORDER BY + LIMIT to TopN
	unique_ptr<LogicalOperator> Optimize(unique_ptr<LogicalOperator> op);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/equal_or_null_simplification.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// Rewrite
// a=b OR (a IS NULL AND b IS NULL) to a IS NOT DISTINCT FROM b
class EqualOrNullSimplification : public Rule {
public:
	explicit EqualOrNullSimplification(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/rule/in_clause_simplification.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

// The in clause simplification rule rewrites cases where left is a column ref with a cast and right are constant values
class InClauseSimplificationRule : public Rule {
public:
	explicit InClauseSimplificationRule(ExpressionRewriter &rewriter);

	unique_ptr<Expression> Apply(LogicalOperator &op, vector<Expression *> &bindings, bool &changes_made,
	                             bool is_root) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/optimizer/matcher/type_matcher_id.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The TypeMatcherId class contains a set of matchers that can be used to pattern match TypeIds for Rules
class TypeMatcherId : public TypeMatcher {
public:
	explicit TypeMatcherId(LogicalTypeId type_id_p) : type_id(type_id_p) {
	}

	bool Match(const LogicalType &type) override {
		return type.id() == this->type_id;
	}

private:
	LogicalTypeId type_id;
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #6
// See the end of this file for a list

// Copyright 2006 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef RE2_REGEXP_H_
#define RE2_REGEXP_H_

// --- SPONSORED LINK --------------------------------------------------
// If you want to use this library for regular expression matching,
// you should use re2/re2.h, which provides a class RE2 that
// mimics the PCRE interface provided by PCRE's C++ wrappers.
// This header describes the low-level interface used to implement RE2
// and may change in backwards-incompatible ways from time to time.
// In contrast, RE2's interface will not.
// ---------------------------------------------------------------------

// Regular expression library: parsing, execution, and manipulation
// of regular expressions.
//
// Any operation that traverses the Regexp structures should be written
// using Regexp::Walker (see walker-inl.h), not recursively, because deeply nested
// regular expressions such as x++++++++++++++++++++... might cause recursive
// traversals to overflow the stack.
//
// It is the caller's responsibility to provide appropriate mutual exclusion
// around manipulation of the regexps.  RE2 does this.
//
// PARSING
//
// Regexp::Parse parses regular expressions encoded in UTF-8.
// The default syntax is POSIX extended regular expressions,
// with the following changes:
//
//   1.  Backreferences (optional in POSIX EREs) are not supported.
//         (Supporting them precludes the use of DFA-based
//          matching engines.)
//
//   2.  Collating elements and collation classes are not supported.
//         (No one has needed or wanted them.)
//
// The exact syntax accepted can be modified by passing flags to
// Regexp::Parse.  In particular, many of the basic Perl additions
// are available.  The flags are documented below (search for LikePerl).
//
// If parsed with the flag Regexp::Latin1, both the regular expression
// and the input to the matching routines are assumed to be encoded in
// Latin-1, not UTF-8.
//
// EXECUTION
//
// Once Regexp has parsed a regular expression, it provides methods
// to search text using that regular expression.  These methods are
// implemented via calling out to other regular expression libraries.
// (Let's call them the sublibraries.)
//
// To call a sublibrary, Regexp does not simply prepare a
// string version of the regular expression and hand it to the
// sublibrary.  Instead, Regexp prepares, from its own parsed form, the
// corresponding internal representation used by the sublibrary.
// This has the drawback of needing to know the internal representation
// used by the sublibrary, but it has two important benefits:
//
//   1. The syntax and meaning of regular expressions is guaranteed
//      to be that used by Regexp's parser, not the syntax expected
//      by the sublibrary.  Regexp might accept a restricted or
//      expanded syntax for regular expressions as compared with
//      the sublibrary.  As long as Regexp can translate from its
//      internal form into the sublibrary's, clients need not know
//      exactly which sublibrary they are using.
//
//   2. The sublibrary parsers are bypassed.  For whatever reason,
//      sublibrary regular expression parsers often have security
//      problems.  For example, plan9grep's regular expression parser
//      has a buffer overflow in its handling of large character
//      classes, and PCRE's parser has had buffer overflow problems
//      in the past.  Security-team requires sandboxing of sublibrary
//      regular expression parsers.  Avoiding the sublibrary parsers
//      avoids the sandbox.
//
// The execution methods we use now are provided by the compiled form,
// Prog, described in prog.h
//
// MANIPULATION
//
// Unlike other regular expression libraries, Regexp makes its parsed
// form accessible to clients, so that client code can analyze the
// parsed regular expressions.

#include <stdint.h>
#include <map>
#include <set>
#include <string>



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #6
// See the end of this file for a list

// Copyright 2009 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef UTIL_UTIL_H_
#define UTIL_UTIL_H_

#define arraysize(array) (int)(sizeof(array)/sizeof((array)[0]))

#ifndef ATTRIBUTE_NORETURN
#if defined(__GNUC__)
#define ATTRIBUTE_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define ATTRIBUTE_NORETURN __declspec(noreturn)
#else
#define ATTRIBUTE_NORETURN
#endif
#endif

#ifndef FALLTHROUGH_INTENDED
#if defined(__clang__)
#define FALLTHROUGH_INTENDED [[clang::fallthrough]]
#elif defined(__GNUC__) && __GNUC__ >= 7
#define FALLTHROUGH_INTENDED [[gnu::fallthrough]]
#else
#define FALLTHROUGH_INTENDED do {} while (0)
#endif
#endif

#ifndef NO_THREAD_SAFETY_ANALYSIS
#define NO_THREAD_SAFETY_ANALYSIS
#endif

#endif  // UTIL_UTIL_H_


// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #6
// See the end of this file for a list

// Copyright 2009 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef UTIL_LOGGING_H_
#define UTIL_LOGGING_H_

// Simplified version of Google's logging.

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <ostream>
#include <sstream>



// Debug-only checking.
#define DCHECK(condition) assert(condition)
#define DCHECK_EQ(val1, val2) assert((val1) == (val2))
#define DCHECK_NE(val1, val2) assert((val1) != (val2))
#define DCHECK_LE(val1, val2) assert((val1) <= (val2))
#define DCHECK_LT(val1, val2) assert((val1) < (val2))
#define DCHECK_GE(val1, val2) assert((val1) >= (val2))
#define DCHECK_GT(val1, val2) assert((val1) > (val2))

// Always-on checking
#define CHECK(x)	if(x){}else LogMessageFatal(__FILE__, __LINE__).stream() << "Check failed: " #x
#define CHECK_LT(x, y)	CHECK((x) < (y))
#define CHECK_GT(x, y)	CHECK((x) > (y))
#define CHECK_LE(x, y)	CHECK((x) <= (y))
#define CHECK_GE(x, y)	CHECK((x) >= (y))
#define CHECK_EQ(x, y)	CHECK((x) == (y))
#define CHECK_NE(x, y)	CHECK((x) != (y))

#define LOG_INFO LogMessage(__FILE__, __LINE__)
#define LOG_WARNING LogMessage(__FILE__, __LINE__)
#define LOG_ERROR LogMessage(__FILE__, __LINE__)
#define LOG_FATAL LogMessageFatal(__FILE__, __LINE__)
#define LOG_QFATAL LOG_FATAL

// It seems that one of the Windows header files defines ERROR as 0.
#ifdef _WIN32
#define LOG_0 LOG_INFO
#endif

#ifdef NDEBUG
#define LOG_DFATAL LOG_ERROR
#else
#define LOG_DFATAL LOG_FATAL
#endif

#define LOG(severity) LOG_ ## severity.stream()

#define VLOG(x) if((x)>0){}else LOG_INFO.stream()

namespace duckdb_re2 {


class LogMessage {
 public:
  LogMessage(const char* file, int line)
      : flushed_(false) {
    stream() << file << ":" << line << ": ";
  }
  void Flush() {
    stream() << "\n";
	/*// R does not allow us to have a reference to stderr even if we are not using it
    std::string s = str_.str();
    size_t n = s.size();
    if (fwrite(s.data(), 1, n, stderr) < n) {}  // shut up gcc
    */
    flushed_ = true;
  }
  ~LogMessage() {
    if (!flushed_) {
      Flush();
    }
  }
  std::ostream& stream() { return str_; }

 private:
  bool flushed_;
  std::ostringstream str_;

  LogMessage(const LogMessage&) = delete;
  LogMessage& operator=(const LogMessage&) = delete;
};

// Silence "destructor never returns" warning for ~LogMessageFatal().
// Since this is a header file, push and then pop to limit the scope.
#ifdef _MSC_VER
//#pragma warning(push)
//#pragma warning(disable: 4722)
#endif

class LogMessageFatal : public LogMessage {
 public:
  LogMessageFatal(const char* file, int line)
      : LogMessage(file, line) {}
  ATTRIBUTE_NORETURN ~LogMessageFatal() {
    Flush();
    abort();
  }
 private:
  LogMessageFatal(const LogMessageFatal&) = delete;
  LogMessageFatal& operator=(const LogMessageFatal&) = delete;
};
} // namespace

#ifdef _MSC_VER
//#pragma warning(pop)
#endif

#endif  // UTIL_LOGGING_H_


// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #6
// See the end of this file for a list

/*
 * The authors of this software are Rob Pike and Ken Thompson.
 *              Copyright (c) 2002 by Lucent Technologies.
 * Permission to use, copy, modify, and distribute this software for any
 * purpose without fee is hereby granted, provided that this entire notice
 * is included in all copies of any software which is or includes a copy
 * or modification of this software and in all copies of the supporting
 * documentation for such software.
 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
 *
 * This file and rune.cc have been converted to compile as C++ code
 * in name space re2.
 */

#ifndef UTIL_UTF_H_
#define UTIL_UTF_H_

#include <stdint.h>

namespace duckdb_re2 {

typedef signed int Rune;	/* Code-point values in Unicode 4.0 are 21 bits wide.*/

enum
{
  UTFmax	= 4,		/* maximum bytes per rune */
  Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
  Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
  Runeerror	= 0xFFFD,	/* decoding error in UTF */
  Runemax	= 0x10FFFF,	/* maximum rune value */
};

int runetochar(char* s, const Rune* r);
int chartorune(Rune* r, const char* s);
int fullrune(const char* s, int n);
int utflen(const char* s);
char* utfrune(const char*, Rune);

}  // namespace duckdb_re2

#endif  // UTIL_UTF_H_


// LICENSE_CHANGE_END



namespace duckdb_re2 {

// Keep in sync with string list kOpcodeNames[] in testing/dump.cc
enum RegexpOp {
  // Matches no strings.
  kRegexpNoMatch = 1,

  // Matches empty string.
  kRegexpEmptyMatch,

  // Matches rune_.
  kRegexpLiteral,

  // Matches runes_.
  kRegexpLiteralString,

  // Matches concatenation of sub_[0..nsub-1].
  kRegexpConcat,
  // Matches union of sub_[0..nsub-1].
  kRegexpAlternate,

  // Matches sub_[0] zero or more times.
  kRegexpStar,
  // Matches sub_[0] one or more times.
  kRegexpPlus,
  // Matches sub_[0] zero or one times.
  kRegexpQuest,

  // Matches sub_[0] at least min_ times, at most max_ times.
  // max_ == -1 means no upper limit.
  kRegexpRepeat,

  // Parenthesized (capturing) subexpression.  Index is cap_.
  // Optionally, capturing name is name_.
  kRegexpCapture,

  // Matches any character.
  kRegexpAnyChar,

  // Matches any byte [sic].
  kRegexpAnyByte,

  // Matches empty string at beginning of line.
  kRegexpBeginLine,
  // Matches empty string at end of line.
  kRegexpEndLine,

  // Matches word boundary "\b".
  kRegexpWordBoundary,
  // Matches not-a-word boundary "\B".
  kRegexpNoWordBoundary,

  // Matches empty string at beginning of text.
  kRegexpBeginText,
  // Matches empty string at end of text.
  kRegexpEndText,

  // Matches character class given by cc_.
  kRegexpCharClass,

  // Forces match of entire expression right now,
  // with match ID match_id_ (used by RE2::Set).
  kRegexpHaveMatch,

  kMaxRegexpOp = kRegexpHaveMatch,
};

// Keep in sync with string list in regexp.cc
enum RegexpStatusCode {
  // No error
  kRegexpSuccess = 0,

  // Unexpected error
  kRegexpInternalError,

  // Parse errors
  kRegexpBadEscape,          // bad escape sequence
  kRegexpBadCharClass,       // bad character class
  kRegexpBadCharRange,       // bad character class range
  kRegexpMissingBracket,     // missing closing ]
  kRegexpMissingParen,       // missing closing )
  kRegexpTrailingBackslash,  // at end of regexp
  kRegexpRepeatArgument,     // repeat argument missing, e.g. "*"
  kRegexpRepeatSize,         // bad repetition argument
  kRegexpRepeatOp,           // bad repetition operator
  kRegexpBadPerlOp,          // bad perl operator
  kRegexpBadUTF8,            // invalid UTF-8 in regexp
  kRegexpBadNamedCapture,    // bad named capture
};

// Error status for certain operations.
class RegexpStatus {
 public:
  RegexpStatus() : code_(kRegexpSuccess), tmp_(NULL) {}
  ~RegexpStatus() { delete tmp_; }

  void set_code(RegexpStatusCode code) { code_ = code; }
  void set_error_arg(const StringPiece& error_arg) { error_arg_ = error_arg; }
  void set_tmp(std::string* tmp) { delete tmp_; tmp_ = tmp; }
  RegexpStatusCode code() const { return code_; }
  const StringPiece& error_arg() const { return error_arg_; }
  bool ok() const { return code() == kRegexpSuccess; }

  // Copies state from status.
  void Copy(const RegexpStatus& status);

  // Returns text equivalent of code, e.g.:
  //   "Bad character class"
  static std::string CodeText(RegexpStatusCode code);

  // Returns text describing error, e.g.:
  //   "Bad character class: [z-a]"
  std::string Text() const;

 private:
  RegexpStatusCode code_;  // Kind of error
  StringPiece error_arg_;  // Piece of regexp containing syntax error.
  std::string* tmp_;       // Temporary storage, possibly where error_arg_ is.

  RegexpStatus(const RegexpStatus&) = delete;
  RegexpStatus& operator=(const RegexpStatus&) = delete;
};

// Compiled form; see prog.h
class Prog;

struct RuneRange {
  RuneRange() : lo(0), hi(0) { }
  RuneRange(int l, int h) : lo(l), hi(h) { }
  Rune lo;
  Rune hi;
};

// Less-than on RuneRanges treats a == b if they overlap at all.
// This lets us look in a set to find the range covering a particular Rune.
struct RuneRangeLess {
  bool operator()(const RuneRange& a, const RuneRange& b) const {
    return a.hi < b.lo;
  }
};

class CharClassBuilder;

class CharClass {
 public:
  void Delete();

  typedef RuneRange* iterator;
  iterator begin() { return ranges_; }
  iterator end() { return ranges_ + nranges_; }

  int size() { return nrunes_; }
  bool empty() { return nrunes_ == 0; }
  bool full() { return nrunes_ == Runemax+1; }
  bool FoldsASCII() { return folds_ascii_; }

  bool Contains(Rune r);
  CharClass* Negate();

 private:
  CharClass();  // not implemented
  ~CharClass();  // not implemented
  static CharClass* New(int maxranges);

  friend class CharClassBuilder;

  bool folds_ascii_;
  int nrunes_;
  RuneRange *ranges_;
  int nranges_;

  CharClass(const CharClass&) = delete;
  CharClass& operator=(const CharClass&) = delete;
};

struct repeat_t {  // Repeat
    int max_;
    int min_;
};

struct capture_t {  // Capture
    int cap_;
    std::string* name_;
};

struct literal_string_t{  // LiteralString
    int nrunes_;
    Rune* runes_;
};

struct char_class_t {  // CharClass
    // These two could be in separate union members,
    // but it wouldn't save any space (there are other two-word structs)
    // and keeping them separate avoids confusion during parsing.
    CharClass* cc_;
    CharClassBuilder* ccb_;
};

class Regexp {
 public:

  // Flags for parsing.  Can be ORed together.
  enum ParseFlags {
    NoParseFlags  = 0,
    FoldCase      = 1<<0,   // Fold case during matching (case-insensitive).
    Literal       = 1<<1,   // Treat s as literal string instead of a regexp.
    ClassNL       = 1<<2,   // Allow char classes like [^a-z] and \D and \s
                            // and [[:space:]] to match newline.
    DotNL         = 1<<3,   // Allow . to match newline.
    MatchNL       = ClassNL | DotNL,
    OneLine       = 1<<4,   // Treat ^ and $ as only matching at beginning and
                            // end of text, not around embedded newlines.
                            // (Perl's default)
    Latin1        = 1<<5,   // Regexp and text are in Latin1, not UTF-8.
    NonGreedy     = 1<<6,   // Repetition operators are non-greedy by default.
    PerlClasses   = 1<<7,   // Allow Perl character classes like \d.
    PerlB         = 1<<8,   // Allow Perl's \b and \B.
    PerlX         = 1<<9,   // Perl extensions:
                            //   non-capturing parens - (?: )
                            //   non-greedy operators - *? +? ?? {}?
                            //   flag edits - (?i) (?-i) (?i: )
                            //     i - FoldCase
                            //     m - !OneLine
                            //     s - DotNL
                            //     U - NonGreedy
                            //   line ends: \A \z
                            //   \Q and \E to disable/enable metacharacters
                            //   (?P<name>expr) for named captures
                            //   \C to match any single byte
    UnicodeGroups = 1<<10,  // Allow \p{Han} for Unicode Han group
                            //   and \P{Han} for its negation.
    NeverNL       = 1<<11,  // Never match NL, even if the regexp mentions
                            //   it explicitly.
    NeverCapture  = 1<<12,  // Parse all parens as non-capturing.

    // As close to Perl as we can get.
    LikePerl      = ClassNL | OneLine | PerlClasses | PerlB | PerlX |
                    UnicodeGroups,

    // Internal use only.
    WasDollar     = 1<<13,  // on kRegexpEndText: was $ in regexp text
    AllParseFlags = (1<<14)-1,
  };

  // Get.  No set, Regexps are logically immutable once created.
  RegexpOp op() { return static_cast<RegexpOp>(op_); }
  int nsub() { return nsub_; }
  bool simple() { return simple_ != 0; }
  ParseFlags parse_flags() { return static_cast<ParseFlags>(parse_flags_); }
  int Ref();  // For testing.

  Regexp** sub() {
    if(nsub_ <= 1)
      return &subone_;
    else
      return submany_;
  }

  int min() { DCHECK_EQ(op_, kRegexpRepeat); return repeat_.min_; }
  int max() { DCHECK_EQ(op_, kRegexpRepeat); return repeat_.max_; }
  Rune rune() { DCHECK_EQ(op_, kRegexpLiteral); return rune_; }
  CharClass* cc() { DCHECK_EQ(op_, kRegexpCharClass); return char_class_.cc_; }
  int cap() { DCHECK_EQ(op_, kRegexpCapture); return capture_.cap_; }
  const std::string* name() { DCHECK_EQ(op_, kRegexpCapture); return capture_.name_; }
  Rune* runes() { DCHECK_EQ(op_, kRegexpLiteralString); return literal_string_.runes_; }
  int nrunes() { DCHECK_EQ(op_, kRegexpLiteralString); return literal_string_.nrunes_; }
  int match_id() { DCHECK_EQ(op_, kRegexpHaveMatch); return match_id_; }

  // Increments reference count, returns object as convenience.
  Regexp* Incref();

  // Decrements reference count and deletes this object if count reaches 0.
  void Decref();

  // Parses string s to produce regular expression, returned.
  // Caller must release return value with re->Decref().
  // On failure, sets *status (if status != NULL) and returns NULL.
  static Regexp* Parse(const StringPiece& s, ParseFlags flags,
                       RegexpStatus* status);

  // Returns a _new_ simplified version of the current regexp.
  // Does not edit the current regexp.
  // Caller must release return value with re->Decref().
  // Simplified means that counted repetition has been rewritten
  // into simpler terms and all Perl/POSIX features have been
  // removed.  The result will capture exactly the same
  // subexpressions the original did, unless formatted with ToString.
  Regexp* Simplify();
  friend class CoalesceWalker;
  friend class SimplifyWalker;

  // Parses the regexp src and then simplifies it and sets *dst to the
  // string representation of the simplified form.  Returns true on success.
  // Returns false and sets *status (if status != NULL) on parse error.
  static bool SimplifyRegexp(const StringPiece& src, ParseFlags flags,
                             std::string* dst, RegexpStatus* status);

  // Returns the number of capturing groups in the regexp.
  int NumCaptures();
  friend class NumCapturesWalker;

  // Returns a map from names to capturing group indices,
  // or NULL if the regexp contains no named capture groups.
  // The caller is responsible for deleting the map.
  std::map<std::string, int>* NamedCaptures();

  // Returns a map from capturing group indices to capturing group
  // names or NULL if the regexp contains no named capture groups. The
  // caller is responsible for deleting the map.
  std::map<int, std::string>* CaptureNames();

  // Returns a string representation of the current regexp,
  // using as few parentheses as possible.
  std::string ToString();

  // Convenience functions.  They consume the passed reference,
  // so in many cases you should use, e.g., Plus(re->Incref(), flags).
  // They do not consume allocated arrays like subs or runes.
  static Regexp* Plus(Regexp* sub, ParseFlags flags);
  static Regexp* Star(Regexp* sub, ParseFlags flags);
  static Regexp* Quest(Regexp* sub, ParseFlags flags);
  static Regexp* Concat(Regexp** subs, int nsubs, ParseFlags flags);
  static Regexp* Alternate(Regexp** subs, int nsubs, ParseFlags flags);
  static Regexp* Capture(Regexp* sub, ParseFlags flags, int cap);
  static Regexp* Repeat(Regexp* sub, ParseFlags flags, int min, int max);
  static Regexp* NewLiteral(Rune rune, ParseFlags flags);
  static Regexp* NewCharClass(CharClass* cc, ParseFlags flags);
  static Regexp* LiteralString(Rune* runes, int nrunes, ParseFlags flags);
  static Regexp* HaveMatch(int match_id, ParseFlags flags);

  // Like Alternate but does not factor out common prefixes.
  static Regexp* AlternateNoFactor(Regexp** subs, int nsubs, ParseFlags flags);

  // Debugging function.  Returns string format for regexp
  // that makes structure clear.  Does NOT use regexp syntax.
  std::string Dump();

  // Helper traversal class, defined fully in walker-inl.h.
  template<typename T> class Walker;

  // Compile to Prog.  See prog.h
  // Reverse prog expects to be run over text backward.
  // Construction and execution of prog will
  // stay within approximately max_mem bytes of memory.
  // If max_mem <= 0, a reasonable default is used.
  Prog* CompileToProg(int64_t max_mem);
  Prog* CompileToReverseProg(int64_t max_mem);

  // Whether to expect this library to find exactly the same answer as PCRE
  // when running this regexp.  Most regexps do mimic PCRE exactly, but a few
  // obscure cases behave differently.  Technically this is more a property
  // of the Prog than the Regexp, but the computation is much easier to do
  // on the Regexp.  See mimics_pcre.cc for the exact conditions.
  bool MimicsPCRE();

  // Benchmarking function.
  void NullWalk();

  // Whether every match of this regexp must be anchored and
  // begin with a non-empty fixed string (perhaps after ASCII
  // case-folding).  If so, returns the prefix and the sub-regexp that
  // follows it.
  // Callers should expect *prefix, *foldcase and *suffix to be "zeroed"
  // regardless of the return value.
  bool RequiredPrefix(std::string* prefix, bool* foldcase,
                      Regexp** suffix);

 private:
  // Constructor allocates vectors as appropriate for operator.
  explicit Regexp(RegexpOp op, ParseFlags parse_flags);

  // Use Decref() instead of delete to release Regexps.
  // This is private to catch deletes at compile time.
  ~Regexp();
  void Destroy();
  bool QuickDestroy();

  // Helpers for Parse.  Listed here so they can edit Regexps.
  class ParseState;

  friend class ParseState;
  friend bool ParseCharClass(StringPiece* s, Regexp** out_re,
                             RegexpStatus* status);

  // Helper for testing [sic].
  friend bool RegexpEqualTestingOnly(Regexp*, Regexp*);

  // Computes whether Regexp is already simple.
  bool ComputeSimple();

  // Constructor that generates a Star, Plus or Quest,
  // squashing the pair if sub is also a Star, Plus or Quest.
  static Regexp* StarPlusOrQuest(RegexpOp op, Regexp* sub, ParseFlags flags);

  // Constructor that generates a concatenation or alternation,
  // enforcing the limit on the number of subexpressions for
  // a particular Regexp.
  static Regexp* ConcatOrAlternate(RegexpOp op, Regexp** subs, int nsubs,
                                   ParseFlags flags, bool can_factor);

  // Returns the leading string that re starts with.
  // The returned Rune* points into a piece of re,
  // so it must not be used after the caller calls re->Decref().
  static Rune* LeadingString(Regexp* re, int* nrune, ParseFlags* flags);

  // Removes the first n leading runes from the beginning of re.
  // Edits re in place.
  static void RemoveLeadingString(Regexp* re, int n);

  // Returns the leading regexp in re's top-level concatenation.
  // The returned Regexp* points at re or a sub-expression of re,
  // so it must not be used after the caller calls re->Decref().
  static Regexp* LeadingRegexp(Regexp* re);

  // Removes LeadingRegexp(re) from re and returns the remainder.
  // Might edit re in place.
  static Regexp* RemoveLeadingRegexp(Regexp* re);

  // Simplifies an alternation of literal strings by factoring out
  // common prefixes.
  static int FactorAlternation(Regexp** sub, int nsub, ParseFlags flags);
  friend class FactorAlternationImpl;

  // Is a == b?  Only efficient on regexps that have not been through
  // Simplify yet - the expansion of a kRegexpRepeat will make this
  // take a long time.  Do not call on such regexps, hence private.
  static bool Equal(Regexp* a, Regexp* b);

  // Allocate space for n sub-regexps.
  void AllocSub(int n) {
    DCHECK(n >= 0 && static_cast<uint16_t>(n) == n);
    if (n > 1)
      submany_ = new Regexp*[n];
    nsub_ = static_cast<uint16_t>(n);
  }

  // Add Rune to LiteralString
  void AddRuneToString(Rune r);

  // Swaps this with that, in place.
  void Swap(Regexp *that);

  // Operator.  See description of operators above.
  // uint8_t instead of RegexpOp to control space usage.
  uint8_t op_;

  // Is this regexp structure already simple
  // (has it been returned by Simplify)?
  // uint8_t instead of bool to control space usage.
  uint8_t simple_;

  // Flags saved from parsing and used during execution.
  // (Only FoldCase is used.)
  // uint16_t instead of ParseFlags to control space usage.
  uint16_t parse_flags_;

  // Reference count.  Exists so that SimplifyRegexp can build
  // regexp structures that are dags rather than trees to avoid
  // exponential blowup in space requirements.
  // uint16_t to control space usage.
  // The standard regexp routines will never generate a
  // ref greater than the maximum repeat count (kMaxRepeat),
  // but even so, Incref and Decref consult an overflow map
  // when ref_ reaches kMaxRef.
  uint16_t ref_;
  static const uint16_t kMaxRef = 0xffff;

  // Subexpressions.
  // uint16_t to control space usage.
  // Concat and Alternate handle larger numbers of subexpressions
  // by building concatenation or alternation trees.
  // Other routines should call Concat or Alternate instead of
  // filling in sub() by hand.
  uint16_t nsub_;
  static const uint16_t kMaxNsub = 0xffff;
  union {
    Regexp** submany_;  // if nsub_ > 1
    Regexp* subone_;  // if nsub_ == 1
  };

  // Extra space for parse and teardown stacks.
  Regexp* down_;

  // Arguments to operator.  See description of operators above.
  union {
    repeat_t repeat_;
    capture_t capture_;
    literal_string_t literal_string_;
    char_class_t char_class_;
    Rune rune_;  // Literal
    int match_id_;  // HaveMatch
    void *the_union_[2];  // as big as any other element, for memset
  };

  Regexp(const Regexp&) = delete;
  Regexp& operator=(const Regexp&) = delete;
};

// Character class set: contains non-overlapping, non-abutting RuneRanges.
typedef std::set<RuneRange, RuneRangeLess> RuneRangeSet;

class CharClassBuilder {
 public:
  CharClassBuilder();

  typedef RuneRangeSet::iterator iterator;
  iterator begin() { return ranges_.begin(); }
  iterator end() { return ranges_.end(); }

  int size() { return nrunes_; }
  bool empty() { return nrunes_ == 0; }
  bool full() { return nrunes_ == Runemax+1; }

  bool Contains(Rune r);
  bool FoldsASCII();
  bool AddRange(Rune lo, Rune hi);  // returns whether class changed
  CharClassBuilder* Copy();
  void AddCharClass(CharClassBuilder* cc);
  void Negate();
  void RemoveAbove(Rune r);
  CharClass* GetCharClass();
  void AddRangeFlags(Rune lo, Rune hi, Regexp::ParseFlags parse_flags);

 private:
  static const uint32_t AlphaMask = (1<<26) - 1;
  uint32_t upper_;  // bitmap of A-Z
  uint32_t lower_;  // bitmap of a-z
  int nrunes_;
  RuneRangeSet ranges_;

  CharClassBuilder(const CharClassBuilder&) = delete;
  CharClassBuilder& operator=(const CharClassBuilder&) = delete;
};

// Bitwise ops on ParseFlags produce ParseFlags.
inline Regexp::ParseFlags operator|(Regexp::ParseFlags a,
                                    Regexp::ParseFlags b) {
  return static_cast<Regexp::ParseFlags>(
      static_cast<int>(a) | static_cast<int>(b));
}

inline Regexp::ParseFlags operator^(Regexp::ParseFlags a,
                                    Regexp::ParseFlags b) {
  return static_cast<Regexp::ParseFlags>(
      static_cast<int>(a) ^ static_cast<int>(b));
}

inline Regexp::ParseFlags operator&(Regexp::ParseFlags a,
                                    Regexp::ParseFlags b) {
  return static_cast<Regexp::ParseFlags>(
      static_cast<int>(a) & static_cast<int>(b));
}

inline Regexp::ParseFlags operator~(Regexp::ParseFlags a) {
  // Attempting to produce a value out of enum's range has undefined behaviour.
  return static_cast<Regexp::ParseFlags>(
      ~static_cast<int>(a) & static_cast<int>(Regexp::AllParseFlags));
}

}  // namespace duckdb_re2

#endif  // RE2_REGEXP_H_


// LICENSE_CHANGE_END
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/statistics/distinct_statistics.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class Serializer;
class Deserializer;
class Vector;

class DistinctStatistics : public BaseStatistics {
public:
	DistinctStatistics();
	explicit DistinctStatistics(unique_ptr<HyperLogLog> log, idx_t sample_count, idx_t total_count);

	//! The HLL of the table
	unique_ptr<HyperLogLog> log;
	//! How many values have been sampled into the HLL
	atomic<idx_t> sample_count;
	//! How many values have been inserted (before sampling)
	atomic<idx_t> total_count;

public:
	void Merge(const BaseStatistics &other) override;

	unique_ptr<BaseStatistics> Copy() const override;

	void Serialize(Serializer &serializer) const override;
	void Serialize(FieldWriter &writer) const override;

	static unique_ptr<DistinctStatistics> Deserialize(Deserializer &source);
	static unique_ptr<DistinctStatistics> Deserialize(FieldReader &reader);

	void Update(Vector &update, idx_t count);
	void Update(VectorData &update_data, const LogicalType &ptype, idx_t count);

	string ToString() const override;
	idx_t GetCount() const;

private:
	//! For distinct statistics we sample the input to speed up insertions
	static constexpr const double SAMPLE_RATE = 0.1;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/pipeline_executor.hpp
//
//
//===----------------------------------------------------------------------===//










#include <functional>

namespace duckdb {
class Executor;

//! The Pipeline class represents an execution pipeline
class PipelineExecutor {
	static constexpr const idx_t CACHE_THRESHOLD = 64;

public:
	PipelineExecutor(ClientContext &context, Pipeline &pipeline);

	//! Fully execute a pipeline with a source and a sink until the source is completely exhausted
	void Execute();
	//! Execute a pipeline with a source and a sink until finished, or until max_chunks have been processed
	//! Returns true if execution is finished, false if Execute should be called again
	bool Execute(idx_t max_chunks);

	//! Push a single input DataChunk into the pipeline.
	//! Returns either OperatorResultType::NEED_MORE_INPUT or OperatorResultType::FINISHED
	//! If OperatorResultType::FINISHED is returned, more input will not change the result anymore
	OperatorResultType ExecutePush(DataChunk &input);
	//! Called after depleting the source: finalizes the execution of this pipeline executor
	//! This should only be called once per PipelineExecutor
	void PushFinalize();

	//! Initializes a chunk with the types that will flow out of ExecutePull
	void InitializeChunk(DataChunk &chunk);
	//! Execute a pipeline without a sink, and retrieve a single DataChunk
	//! Returns an empty chunk when finished.
	void ExecutePull(DataChunk &result);
	//! Called after depleting the source using ExecutePull
	//! This flushes profiler states
	void PullFinalize();

private:
	//! The pipeline to process
	Pipeline &pipeline;
	//! The thread context of this executor
	ThreadContext thread;
	//! The total execution context of this executor
	ExecutionContext context;

	//! Intermediate chunks for the operators
	vector<unique_ptr<DataChunk>> intermediate_chunks;
	//! Intermediate states for the operators
	vector<unique_ptr<OperatorState>> intermediate_states;

	//! The local source state
	unique_ptr<LocalSourceState> local_source_state;
	//! The local sink state (if any)
	unique_ptr<LocalSinkState> local_sink_state;

	//! The final chunk used for moving data into the sink
	DataChunk final_chunk;

	//! The operators that are not yet finished executing and have data remaining
	//! If the stack of in_process_operators is empty, we fetch from the source instead
	stack<idx_t> in_process_operators;
	//! Whether or not the pipeline has been finalized (used for verification only)
	bool finalized = false;
	//! Whether or not the pipeline has finished processing
	int32_t finished_processing_idx = -1;
	//! Whether or not this pipeline requires keeping track of the batch index of the source
	bool requires_batch_index = false;

	//! Cached chunks for any operators that require caching
	vector<unique_ptr<DataChunk>> cached_chunks;

private:
	void StartOperator(PhysicalOperator *op);
	void EndOperator(PhysicalOperator *op, DataChunk *chunk);

	//! Reset the operator index to the first operator
	void GoToSource(idx_t &current_idx, idx_t initial_idx);
	void FetchFromSource(DataChunk &result);

	void FinishProcessing(int32_t operator_idx = -1);
	bool IsFinished();

	OperatorResultType ExecutePushInternal(DataChunk &input, idx_t initial_idx = 0);
	//! Pushes a chunk through the pipeline and returns a single result chunk
	//! Returns whether or not a new input chunk is needed, or whether or not we are finished
	OperatorResultType Execute(DataChunk &input, DataChunk &result, idx_t initial_index = 0);

	static bool CanCacheType(const LogicalType &type);
	void CacheChunk(DataChunk &input, idx_t operator_idx);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/pipeline_event.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class PipelineEvent : public Event {
public:
	PipelineEvent(shared_ptr<Pipeline> pipeline);

	//! The pipeline that this event belongs to
	shared_ptr<Pipeline> pipeline;

public:
	void Schedule() override;
	void FinishEvent() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/pipeline_finish_event.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class Executor;

class PipelineFinishEvent : public Event {
public:
	PipelineFinishEvent(shared_ptr<Pipeline> pipeline);

	//! The pipeline that this event belongs to
	shared_ptr<Pipeline> pipeline;

public:
	void Schedule() override;
	void FinishEvent() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parallel/pipeline_complete_event.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class Executor;

class PipelineCompleteEvent : public Event {
public:
	PipelineCompleteEvent(Executor &executor, bool complete_pipeline_p);

	bool complete_pipeline;

public:
	void Schedule() override;
	void FinalizeFinish() override;
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #10
// See the end of this file for a list

// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue.
// An overview, including benchmark results, is provided here:
//     http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++
// The full design is also described in excruciating detail at:
//    http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue

// Simplified BSD license:
// Copyright (c) 2013-2016, Cameron Desrochers.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.




#if defined(__GNUC__)
// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and
// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings
// upon assigning any computed values)

#endif

#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif

#include <atomic>		// Requires C++11. Sorry VS2010.
#include <cassert>
#include <cstddef>              // for max_align_t
#include <cstdint>
#include <cstdlib>
#include <type_traits>
#include <algorithm>
#include <utility>
#include <limits>
#include <climits>		// for CHAR_BIT
#include <array>
#include <thread>		// partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading

// Platform-specific definitions of a numeric thread ID type and an invalid value
namespace duckdb_moodycamel { namespace details {
	template<typename thread_id_t> struct thread_id_converter {
		typedef thread_id_t thread_id_numeric_size_t;
		typedef thread_id_t thread_id_hash_t;
		static thread_id_hash_t prehash(thread_id_t const& x) { return x; }
	};
} }
#if defined(MCDBGQ_USE_RELACY)
namespace duckdb_moodycamel { namespace details {
	typedef std::uint32_t thread_id_t;
	static const thread_id_t invalid_thread_id  = 0xFFFFFFFFU;
	static const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU;
	static inline thread_id_t thread_id() { return rl::thread_index(); }
} }
#elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)
// No sense pulling in windows.h in a header, we'll manually declare the function
// we use and rely on backwards-compatibility for this not to break
extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void);
namespace duckdb_moodycamel { namespace details {
	static_assert(sizeof(unsigned long) == sizeof(std::uint32_t), "Expected size of unsigned long to be 32 bits on Windows");
	typedef std::uint32_t thread_id_t;
	static const thread_id_t invalid_thread_id  = 0;			// See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx
	static const thread_id_t invalid_thread_id2 = 0xFFFFFFFFU;	// Not technically guaranteed to be invalid, but is never used in practice. Note that all Win32 thread IDs are presently multiples of 4.
	static inline thread_id_t thread_id() { return static_cast<thread_id_t>(::GetCurrentThreadId()); }
} }
#elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || (defined(__APPLE__) && TARGET_OS_IPHONE)
namespace duckdb_moodycamel { namespace details {
	static_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, "std::thread::id is expected to be either 4 or 8 bytes");
	
	typedef std::thread::id thread_id_t;
	static const thread_id_t invalid_thread_id;         // Default ctor creates invalid ID

	// Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's
	// only used if MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't
	// be.
	static inline thread_id_t thread_id() { return std::this_thread::get_id(); }

	template<std::size_t> struct thread_id_size { };
	template<> struct thread_id_size<4> { typedef std::uint32_t numeric_t; };
	template<> struct thread_id_size<8> { typedef std::uint64_t numeric_t; };

	template<> struct thread_id_converter<thread_id_t> {
		typedef thread_id_size<sizeof(thread_id_t)>::numeric_t thread_id_numeric_size_t;
#ifndef __APPLE__
		typedef std::size_t thread_id_hash_t;
#else
		typedef thread_id_numeric_size_t thread_id_hash_t;
#endif

		static thread_id_hash_t prehash(thread_id_t const& x)
		{
#ifndef __APPLE__
			return std::hash<std::thread::id>()(x);
#else
			return *reinterpret_cast<thread_id_hash_t const*>(&x);
#endif
		}
	};
} }
#else
// Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475
// In order to get a numeric thread ID in a platform-independent way, we use a thread-local
// static variable's address as a thread identifier :-)
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define MOODYCAMEL_THREADLOCAL __thread
#elif defined(_MSC_VER)
#define MOODYCAMEL_THREADLOCAL __declspec(thread)
#else
// Assume C++11 compliant compiler
#define MOODYCAMEL_THREADLOCAL thread_local
#endif
namespace duckdb_moodycamel { namespace details {
	typedef std::uintptr_t thread_id_t;
	static const thread_id_t invalid_thread_id  = 0;		// Address can't be nullptr
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
	static const thread_id_t invalid_thread_id2 = 1;		// Member accesses off a null pointer are also generally invalid. Plus it's not aligned.
#endif
	inline thread_id_t thread_id() { static MOODYCAMEL_THREADLOCAL int x; return reinterpret_cast<thread_id_t>(&x); }
} }
#endif

// Constexpr if
#ifndef MOODYCAMEL_CONSTEXPR_IF
#if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || __cplusplus > 201402L
#define MOODYCAMEL_CONSTEXPR_IF if constexpr
#define MOODYCAMEL_MAYBE_UNUSED [[maybe_unused]]
#else
#define MOODYCAMEL_CONSTEXPR_IF if
#define MOODYCAMEL_MAYBE_UNUSED
#endif
#endif

// Exceptions
#ifndef MOODYCAMEL_EXCEPTIONS_ENABLED
#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__))
#define MOODYCAMEL_EXCEPTIONS_ENABLED
#endif
#endif
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
#define MOODYCAMEL_TRY try
#define MOODYCAMEL_CATCH(...) catch(__VA_ARGS__)
#define MOODYCAMEL_RETHROW throw
#define MOODYCAMEL_THROW(expr) throw (expr)
#else
#define MOODYCAMEL_TRY MOODYCAMEL_CONSTEXPR_IF (true)
#define MOODYCAMEL_CATCH(...) else MOODYCAMEL_CONSTEXPR_IF (false)
#define MOODYCAMEL_RETHROW
#define MOODYCAMEL_THROW(expr)
#endif

#ifndef MOODYCAMEL_NOEXCEPT
#if !defined(MOODYCAMEL_EXCEPTIONS_ENABLED)
#define MOODYCAMEL_NOEXCEPT
#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) true
#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) true
#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800
// VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it shouldn't :-(
// We have to assume *all* non-trivial constructors may throw on VS2012!
#define MOODYCAMEL_NOEXCEPT _NOEXCEPT
#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference<valueType>::value && std::is_move_constructible<type>::value ? std::is_trivially_move_constructible<type>::value : std::is_trivially_copy_constructible<type>::value)
#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference<valueType>::value && std::is_move_assignable<type>::value ? std::is_trivially_move_assignable<type>::value || std::is_nothrow_move_assignable<type>::value : std::is_trivially_copy_assignable<type>::value || std::is_nothrow_copy_assignable<type>::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr))
#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900
#define MOODYCAMEL_NOEXCEPT _NOEXCEPT
#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference<valueType>::value && std::is_move_constructible<type>::value ? std::is_trivially_move_constructible<type>::value || std::is_nothrow_move_constructible<type>::value : std::is_trivially_copy_constructible<type>::value || std::is_nothrow_copy_constructible<type>::value)
#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference<valueType>::value && std::is_move_assignable<type>::value ? std::is_trivially_move_assignable<type>::value || std::is_nothrow_move_assignable<type>::value : std::is_trivially_copy_assignable<type>::value || std::is_nothrow_copy_assignable<type>::value) && MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr))
#else
#define MOODYCAMEL_NOEXCEPT noexcept
#define MOODYCAMEL_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr)
#define MOODYCAMEL_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr)
#endif
#endif

#ifndef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
#ifdef MCDBGQ_USE_RELACY
#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
#else
// VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling bug: http://sourceforge.net/p/mingw-w64/bugs/445
// g++ <=4.7 doesn't support thread_local either.
// Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to compile but it's unconfirmed to actually work
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && (!defined(__MINGW32__) && !defined(__MINGW64__) || !defined(__WINPTHREADS_VERSION)) && (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
// Assume `thread_local` is fully supported in all other C++11 compilers/platforms
//#define MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED    // always disabled for now since several users report having problems with it on
#endif
#endif
#endif

// VS2012 doesn't support deleted functions. 
// In this case, we declare the function normally but don't define it. A link error will be generated if the function is called.
#ifndef MOODYCAMEL_DELETE_FUNCTION
#if defined(_MSC_VER) && _MSC_VER < 1800
#define MOODYCAMEL_DELETE_FUNCTION
#else
#define MOODYCAMEL_DELETE_FUNCTION = delete
#endif
#endif

#ifndef MOODYCAMEL_ALIGNAS
// VS2013 doesn't support alignas or alignof
#if defined(_MSC_VER) && _MSC_VER <= 1800
#define MOODYCAMEL_ALIGNAS(alignment) __declspec(align(alignment))
#define MOODYCAMEL_ALIGNOF(obj) __alignof(obj)
#else
#define MOODYCAMEL_ALIGNAS(alignment) alignas(alignment)
#define MOODYCAMEL_ALIGNOF(obj) alignof(obj)
#endif
#endif



// Compiler-specific likely/unlikely hints
namespace duckdb_moodycamel { namespace details {

#if defined(__GNUC__)
	static inline bool (likely)(bool x) { return __builtin_expect((x), true); }
//	static inline bool (unlikely)(bool x) { return __builtin_expect((x), false); }
#else
	static inline bool (likely)(bool x) { return x; }
//	static inline bool (unlikely)(bool x) { return x; }
#endif
} }

namespace duckdb_moodycamel {
namespace details {
	template<typename T>
	struct const_numeric_max {
		static_assert(std::is_integral<T>::value, "const_numeric_max can only be used with integers");
		static const T value = std::numeric_limits<T>::is_signed
			? (static_cast<T>(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast<T>(1)
			: static_cast<T>(-1);
	};

#if defined(__GLIBCXX__)
	typedef ::max_align_t std_max_align_t;      // libstdc++ forgot to add it to std:: for a while
#else
	typedef std::max_align_t std_max_align_t;   // Others (e.g. MSVC) insist it can *only* be accessed via std::
#endif

	// Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting
	// 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64.
	typedef union {
		std_max_align_t x;
		long long y;
		void* z;
	} max_align_t;
}

// Default traits for the ConcurrentQueue. To change some of the
// traits without re-implementing all of them, inherit from this
// struct and shadow the declarations you wish to be different;
// since the traits are used as a template type parameter, the
// shadowed declarations will be used where defined, and the defaults
// otherwise.
struct ConcurrentQueueDefaultTraits
{
	// General-purpose size type. std::size_t is strongly recommended.
	typedef std::size_t size_t;
	
	// The type used for the enqueue and dequeue indices. Must be at least as
	// large as size_t. Should be significantly larger than the number of elements
	// you expect to hold at once, especially if you have a high turnover rate;
	// for example, on 32-bit x86, if you expect to have over a hundred million
	// elements or pump several million elements through your queue in a very
	// short space of time, using a 32-bit type *may* trigger a race condition.
	// A 64-bit int type is recommended in that case, and in practice will
	// prevent a race condition no matter the usage of the queue. Note that
	// whether the queue is lock-free with a 64-int type depends on the whether
	// std::atomic<std::uint64_t> is lock-free, which is platform-specific.
	typedef std::size_t index_t;
	
	// Internally, all elements are enqueued and dequeued from multi-element
	// blocks; this is the smallest controllable unit. If you expect few elements
	// but many producers, a smaller block size should be favoured. For few producers
	// and/or many elements, a larger block size is preferred. A sane default
	// is provided. Must be a power of 2.
	static const size_t BLOCK_SIZE = 32;
	
	// For explicit producers (i.e. when using a producer token), the block is
	// checked for being empty by iterating through a list of flags, one per element.
	// For large block sizes, this is too inefficient, and switching to an atomic
	// counter-based approach is faster. The switch is made for block sizes strictly
	// larger than this threshold.
	static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32;
	
	// How many full blocks can be expected for a single explicit producer? This should
	// reflect that number's maximum for optimal performance. Must be a power of 2.
	static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32;
	
	// How many full blocks can be expected for a single implicit producer? This should
	// reflect that number's maximum for optimal performance. Must be a power of 2.
	static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32;
	
	// The initial size of the hash table mapping thread IDs to implicit producers.
	// Note that the hash is resized every time it becomes half full.
	// Must be a power of two, and either 0 or at least 1. If 0, implicit production
	// (using the enqueue methods without an explicit producer token) is disabled.
	static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32;
	
	// Controls the number of items that an explicit consumer (i.e. one with a token)
	// must consume before it causes all consumers to rotate and move on to the next
	// internal queue.
	static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256;
	
	// The maximum number of elements (inclusive) that can be enqueued to a sub-queue.
	// Enqueue operations that would cause this limit to be surpassed will fail. Note
	// that this limit is enforced at the block level (for performance reasons), i.e.
	// it's rounded up to the nearest block size.
	static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max<size_t>::value;
	
	
#ifndef MCDBGQ_USE_RELACY
	// Memory allocation can be customized if needed.
	// malloc should return nullptr on failure, and handle alignment like std::malloc.
#if defined(malloc) || defined(free)
	// Gah, this is 2015, stop defining macros that break standard code already!
	// Work around malloc/free being special macros:
	static inline void* WORKAROUND_malloc(size_t size) { return malloc(size); }
	static inline void WORKAROUND_free(void* ptr) { return free(ptr); }
	static inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); }
	static inline void (free)(void* ptr) { return WORKAROUND_free(ptr); }
#else
	static inline void* malloc(size_t size) { return std::malloc(size); }
	static inline void free(void* ptr) { return std::free(ptr); }
#endif
#else
	// Debug versions when running under the Relacy race detector (ignore
	// these in user code)
	static inline void* malloc(size_t size) { return rl::rl_malloc(size, $); }
	static inline void free(void* ptr) { return rl::rl_free(ptr, $); }
#endif
};


// When producing or consuming many elements, the most efficient way is to:
//    1) Use one of the bulk-operation methods of the queue with a token
//    2) Failing that, use the bulk-operation methods without a token
//    3) Failing that, create a token and use that with the single-item methods
//    4) Failing that, use the single-parameter methods of the queue
// Having said that, don't create tokens willy-nilly -- ideally there should be
// a maximum of one token per thread (of each kind).
struct ProducerToken;
struct ConsumerToken;

template<typename T, typename Traits> class ConcurrentQueue;
template<typename T, typename Traits> class BlockingConcurrentQueue;
class ConcurrentQueueTests;


namespace details
{
	struct ConcurrentQueueProducerTypelessBase
	{
		ConcurrentQueueProducerTypelessBase* next;
		std::atomic<bool> inactive;
		ProducerToken* token;
		
		ConcurrentQueueProducerTypelessBase()
			: next(nullptr), inactive(false), token(nullptr)
		{
		}
	};
	
	template<bool use32> struct _hash_32_or_64 {
		static inline std::uint32_t hash(std::uint32_t h)
		{
			// MurmurHash3 finalizer -- see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
			// Since the thread ID is already unique, all we really want to do is propagate that
			// uniqueness evenly across all the bits, so that we can use a subset of the bits while
			// reducing collisions significantly
			h ^= h >> 16;
			h *= 0x85ebca6b;
			h ^= h >> 13;
			h *= 0xc2b2ae35;
			return h ^ (h >> 16);
		}
	};
	template<> struct _hash_32_or_64<1> {
		static inline std::uint64_t hash(std::uint64_t h)
		{
			h ^= h >> 33;
			h *= 0xff51afd7ed558ccd;
			h ^= h >> 33;
			h *= 0xc4ceb9fe1a85ec53;
			return h ^ (h >> 33);
		}
	};
	template<std::size_t size> struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> {  };
	
	static inline size_t hash_thread_id(thread_id_t id)
	{
		static_assert(sizeof(thread_id_t) <= 8, "Expected a platform where thread IDs are at most 64-bit values");
		return static_cast<size_t>(hash_32_or_64<sizeof(thread_id_converter<thread_id_t>::thread_id_hash_t)>::hash(
			thread_id_converter<thread_id_t>::prehash(id)));
	}
	
	template<typename T>
	static inline bool circular_less_than(T a, T b)
	{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4554)
#endif
		static_assert(std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, "circular_less_than is intended to be used only with unsigned integer types");
		return static_cast<T>(a - b) > static_cast<T>(static_cast<T>(1) << static_cast<T>(sizeof(T) * CHAR_BIT - 1));
#ifdef _MSC_VER
#pragma warning(pop)
#endif
	}
	
	template<typename U>
	static inline char* align_for(char* ptr)
	{
		const std::size_t alignment = std::alignment_of<U>::value;
		return ptr + (alignment - (reinterpret_cast<std::uintptr_t>(ptr) % alignment)) % alignment;
	}

	template<typename T>
	static inline T ceil_to_pow_2(T x)
	{
		static_assert(std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, "ceil_to_pow_2 is intended to be used only with unsigned integer types");

		// Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
		--x;
		x |= x >> 1;
		x |= x >> 2;
		x |= x >> 4;
		for (std::size_t i = 1; i < sizeof(T); i <<= 1) {
			x |= x >> (i << 3);
		}
		++x;
		return x;
	}
	
	template<typename T>
	static inline void swap_relaxed(std::atomic<T>& left, std::atomic<T>& right)
	{
		T temp = std::move(left.load(std::memory_order_relaxed));
		left.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed);
		right.store(std::move(temp), std::memory_order_relaxed);
	}
	
	template<typename T>
	static inline T const& nomove(T const& x)
	{
		return x;
	}
	
	template<bool Enable>
	struct nomove_if
	{
		template<typename T>
		static inline T const& eval(T const& x)
		{
			return x;
		}
	};
	
	template<>
	struct nomove_if<false>
	{
		template<typename U>
		static inline auto eval(U&& x)
			-> decltype(std::forward<U>(x))
		{
			return std::forward<U>(x);
		}
	};
	
	template<typename It>
	static inline auto deref_noexcept(It& it) MOODYCAMEL_NOEXCEPT -> decltype(*it)
	{
		return *it;
	}
	
#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
	template<typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> { };
#else
	template<typename T> struct is_trivially_destructible : std::has_trivial_destructor<T> { };
#endif
	
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
#ifdef MCDBGQ_USE_RELACY
	typedef RelacyThreadExitListener ThreadExitListener;
	typedef RelacyThreadExitNotifier ThreadExitNotifier;
#else
	struct ThreadExitListener
	{
		typedef void (*callback_t)(void*);
		callback_t callback;
		void* userData;
		
		ThreadExitListener* next;		// reserved for use by the ThreadExitNotifier
	};
	
	
	class ThreadExitNotifier
	{
	public:
		static void subscribe(ThreadExitListener* listener)
		{
			auto& tlsInst = instance();
			listener->next = tlsInst.tail;
			tlsInst.tail = listener;
		}
		
		static void unsubscribe(ThreadExitListener* listener)
		{
			auto& tlsInst = instance();
			ThreadExitListener** prev = &tlsInst.tail;
			for (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) {
				if (ptr == listener) {
					*prev = ptr->next;
					break;
				}
				prev = &ptr->next;
			}
		}
		
	private:
		ThreadExitNotifier() : tail(nullptr) { }
		ThreadExitNotifier(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION;
		ThreadExitNotifier& operator=(ThreadExitNotifier const&) MOODYCAMEL_DELETE_FUNCTION;
		
		~ThreadExitNotifier()
		{
			// This thread is about to exit, let everyone know!
			assert(this == &instance() && "If this assert fails, you likely have a buggy compiler! Change the preprocessor conditions such that MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined.");
			for (auto ptr = tail; ptr != nullptr; ptr = ptr->next) {
				ptr->callback(ptr->userData);
			}
		}
		
		// Thread-local
		static inline ThreadExitNotifier& instance()
		{
			static thread_local ThreadExitNotifier notifier;
			return notifier;
		}
		
	private:
		ThreadExitListener* tail;
	};
#endif
#endif
	
	template<typename T> struct static_is_lock_free_num { enum { value = 0 }; };
	template<> struct static_is_lock_free_num<signed char> { enum { value = ATOMIC_CHAR_LOCK_FREE }; };
	template<> struct static_is_lock_free_num<short> { enum { value = ATOMIC_SHORT_LOCK_FREE }; };
	template<> struct static_is_lock_free_num<int> { enum { value = ATOMIC_INT_LOCK_FREE }; };
	template<> struct static_is_lock_free_num<long> { enum { value = ATOMIC_LONG_LOCK_FREE }; };
	template<> struct static_is_lock_free_num<long long> { enum { value = ATOMIC_LLONG_LOCK_FREE }; };
	template<typename T> struct static_is_lock_free : static_is_lock_free_num<typename std::make_signed<T>::type> {  };
	template<> struct static_is_lock_free<bool> { enum { value = ATOMIC_BOOL_LOCK_FREE }; };
	template<typename U> struct static_is_lock_free<U*> { enum { value = ATOMIC_POINTER_LOCK_FREE }; };
}


struct ProducerToken
{
	template<typename T, typename Traits>
	explicit ProducerToken(ConcurrentQueue<T, Traits>& queue);
	
	template<typename T, typename Traits>
	explicit ProducerToken(BlockingConcurrentQueue<T, Traits>& queue);
	
	ProducerToken(ProducerToken&& other) MOODYCAMEL_NOEXCEPT
		: producer(other.producer)
	{
		other.producer = nullptr;
		if (producer != nullptr) {
			producer->token = this;
		}
	}
	
	inline ProducerToken& operator=(ProducerToken&& other) MOODYCAMEL_NOEXCEPT
	{
		swap(other);
		return *this;
	}
	
	void swap(ProducerToken& other) MOODYCAMEL_NOEXCEPT
	{
		std::swap(producer, other.producer);
		if (producer != nullptr) {
			producer->token = this;
		}
		if (other.producer != nullptr) {
			other.producer->token = &other;
		}
	}
	
	// A token is always valid unless:
	//     1) Memory allocation failed during construction
	//     2) It was moved via the move constructor
	//        (Note: assignment does a swap, leaving both potentially valid)
	//     3) The associated queue was destroyed
	// Note that if valid() returns true, that only indicates
	// that the token is valid for use with a specific queue,
	// but not which one; that's up to the user to track.
	inline bool valid() const { return producer != nullptr; }
	
	~ProducerToken()
	{
		if (producer != nullptr) {
			producer->token = nullptr;
			producer->inactive.store(true, std::memory_order_release);
		}
	}
	
	// Disable copying and assignment
	ProducerToken(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION;
	ProducerToken& operator=(ProducerToken const&) MOODYCAMEL_DELETE_FUNCTION;
	
private:
	template<typename T, typename Traits> friend class ConcurrentQueue;
	friend class ConcurrentQueueTests;
	
protected:
	details::ConcurrentQueueProducerTypelessBase* producer;
};


struct ConsumerToken
{
	template<typename T, typename Traits>
	explicit ConsumerToken(ConcurrentQueue<T, Traits>& q);
	
	template<typename T, typename Traits>
	explicit ConsumerToken(BlockingConcurrentQueue<T, Traits>& q);
	
	ConsumerToken(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT
		: initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer)
	{
	}
	
	inline ConsumerToken& operator=(ConsumerToken&& other) MOODYCAMEL_NOEXCEPT
	{
		swap(other);
		return *this;
	}
	
	void swap(ConsumerToken& other) MOODYCAMEL_NOEXCEPT
	{
		std::swap(initialOffset, other.initialOffset);
		std::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset);
		std::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent);
		std::swap(currentProducer, other.currentProducer);
		std::swap(desiredProducer, other.desiredProducer);
	}
	
	// Disable copying and assignment
	ConsumerToken(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION;
	ConsumerToken& operator=(ConsumerToken const&) MOODYCAMEL_DELETE_FUNCTION;

private:
	template<typename T, typename Traits> friend class ConcurrentQueue;
	friend class ConcurrentQueueTests;
	
private: // but shared with ConcurrentQueue
	std::uint32_t initialOffset;
	std::uint32_t lastKnownGlobalOffset;
	std::uint32_t itemsConsumedFromCurrent;
	details::ConcurrentQueueProducerTypelessBase* currentProducer;
	details::ConcurrentQueueProducerTypelessBase* desiredProducer;
};

// Need to forward-declare this swap because it's in a namespace.
// See http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces
template<typename T, typename Traits>
inline void swap(typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& a, typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT;


template<typename T, typename Traits = ConcurrentQueueDefaultTraits>
class ConcurrentQueue
{
public:
	typedef ::duckdb_moodycamel::ProducerToken producer_token_t;
	typedef ::duckdb_moodycamel::ConsumerToken consumer_token_t;
	
	typedef typename Traits::index_t index_t;
	typedef typename Traits::size_t size_t;
	
	static const size_t BLOCK_SIZE = static_cast<size_t>(Traits::BLOCK_SIZE);
	static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast<size_t>(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD);
	static const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast<size_t>(Traits::EXPLICIT_INITIAL_INDEX_SIZE);
	static const size_t IMPLICIT_INITIAL_INDEX_SIZE = static_cast<size_t>(Traits::IMPLICIT_INITIAL_INDEX_SIZE);
	static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = static_cast<size_t>(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE);
	static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast<std::uint32_t>(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE);
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4307)		// + integral constant overflow (that's what the ternary expression is for!)
#pragma warning(disable: 4309)		// static_cast: Truncation of constant value
#endif
	static const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max<size_t>::value - static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max<size_t>::value : ((static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE);
#ifdef _MSC_VER
#pragma warning(pop)
#endif

	static_assert(!std::numeric_limits<size_t>::is_signed && std::is_integral<size_t>::value, "Traits::size_t must be an unsigned integral type");
	static_assert(!std::numeric_limits<index_t>::is_signed && std::is_integral<index_t>::value, "Traits::index_t must be an unsigned integral type");
	static_assert(sizeof(index_t) >= sizeof(size_t), "Traits::index_t must be at least as wide as Traits::size_t");
	static_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), "Traits::BLOCK_SIZE must be a power of 2 (and at least 2)");
	static_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), "Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)");
	static_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)");
	static_assert((IMPLICIT_INITIAL_INDEX_SIZE > 1) && !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)");
	static_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2");
	static_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 to disable implicit enqueueing)");

public:
	// Creates a queue with at least `capacity` element slots; note that the
	// actual number of elements that can be inserted without additional memory
	// allocation depends on the number of producers and the block size (e.g. if
	// the block size is equal to `capacity`, only a single block will be allocated
	// up-front, which means only a single producer will be able to enqueue elements
	// without an extra allocation -- blocks aren't shared between producers).
	// This method is not thread safe -- it is up to the user to ensure that the
	// queue is fully constructed before it starts being used by other threads (this
	// includes making the memory effects of construction visible, possibly with a
	// memory barrier).
	explicit ConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE)
		: producerListTail(nullptr),
		producerCount(0),
		initialBlockPoolIndex(0),
		nextExplicitConsumerId(0),
		globalExplicitConsumerOffset(0)
	{
		implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);
		populate_initial_implicit_producer_hash();
		populate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1));
		
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
		// Track all the producers using a fully-resolved typed list for
		// each kind; this makes it possible to debug them starting from
		// the root queue object (otherwise wacky casts are needed that
		// don't compile in the debugger's expression evaluator).
		explicitProducers.store(nullptr, std::memory_order_relaxed);
		implicitProducers.store(nullptr, std::memory_order_relaxed);
#endif
	}
	
	// Computes the correct amount of pre-allocated blocks for you based
	// on the minimum number of elements you want available at any given
	// time, and the maximum concurrent number of each type of producer.
	ConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers)
		: producerListTail(nullptr),
		producerCount(0),
		initialBlockPoolIndex(0),
		nextExplicitConsumerId(0),
		globalExplicitConsumerOffset(0)
	{
		implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);
		populate_initial_implicit_producer_hash();
		size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers);
		populate_initial_block_list(blocks);
		
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
		explicitProducers.store(nullptr, std::memory_order_relaxed);
		implicitProducers.store(nullptr, std::memory_order_relaxed);
#endif
	}
	
	// Note: The queue should not be accessed concurrently while it's
	// being deleted. It's up to the user to synchronize this.
	// This method is not thread safe.
	~ConcurrentQueue()
	{
		// Destroy producers
		auto ptr = producerListTail.load(std::memory_order_relaxed);
		while (ptr != nullptr) {
			auto next = ptr->next_prod();
			if (ptr->token != nullptr) {
				ptr->token->producer = nullptr;
			}
			destroy(ptr);
			ptr = next;
		}
		
		// Destroy implicit producer hash tables
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) {
			auto hash = implicitProducerHash.load(std::memory_order_relaxed);
			while (hash != nullptr) {
				auto prev = hash->prev;
				if (prev != nullptr) {		// The last hash is part of this object and was not allocated dynamically
					for (size_t i = 0; i != hash->capacity; ++i) {
						hash->entries[i].~ImplicitProducerKVP();
					}
					hash->~ImplicitProducerHash();
					(Traits::free)(hash);
				}
				hash = prev;
			}
		}
		
		// Destroy global free list
		auto block = freeList.head_unsafe();
		while (block != nullptr) {
			auto next = block->freeListNext.load(std::memory_order_relaxed);
			if (block->dynamicallyAllocated) {
				destroy(block);
			}
			block = next;
		}
		
		// Destroy initial free list
		destroy_array(initialBlockPool, initialBlockPoolSize);
	}

	// Disable copying and copy assignment
	ConcurrentQueue(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;
	ConcurrentQueue& operator=(ConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;
	
	// Moving is supported, but note that it is *not* a thread-safe operation.
	// Nobody can use the queue while it's being moved, and the memory effects
	// of that move must be propagated to other threads before they can use it.
	// Note: When a queue is moved, its tokens are still valid but can only be
	// used with the destination queue (i.e. semantically they are moved along
	// with the queue itself).
	ConcurrentQueue(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT
		: producerListTail(other.producerListTail.load(std::memory_order_relaxed)),
		producerCount(other.producerCount.load(std::memory_order_relaxed)),
		initialBlockPoolIndex(other.initialBlockPoolIndex.load(std::memory_order_relaxed)),
		initialBlockPool(other.initialBlockPool),
		initialBlockPoolSize(other.initialBlockPoolSize),
		freeList(std::move(other.freeList)),
		nextExplicitConsumerId(other.nextExplicitConsumerId.load(std::memory_order_relaxed)),
		globalExplicitConsumerOffset(other.globalExplicitConsumerOffset.load(std::memory_order_relaxed))
	{
		// Move the other one into this, and leave the other one as an empty queue
		implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);
		populate_initial_implicit_producer_hash();
		swap_implicit_producer_hashes(other);
		
		other.producerListTail.store(nullptr, std::memory_order_relaxed);
		other.producerCount.store(0, std::memory_order_relaxed);
		other.nextExplicitConsumerId.store(0, std::memory_order_relaxed);
		other.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed);
		
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
		explicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed);
		other.explicitProducers.store(nullptr, std::memory_order_relaxed);
		implicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed);
		other.implicitProducers.store(nullptr, std::memory_order_relaxed);
#endif
		
		other.initialBlockPoolIndex.store(0, std::memory_order_relaxed);
		other.initialBlockPoolSize = 0;
		other.initialBlockPool = nullptr;
		
		reown_producers();
	}
	
	inline ConcurrentQueue& operator=(ConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT
	{
		return swap_internal(other);
	}
	
	// Swaps this queue's state with the other's. Not thread-safe.
	// Swapping two queues does not invalidate their tokens, however
	// the tokens that were created for one queue must be used with
	// only the swapped queue (i.e. the tokens are tied to the
	// queue's movable state, not the object itself).
	inline void swap(ConcurrentQueue& other) MOODYCAMEL_NOEXCEPT
	{
		swap_internal(other);
	}
	
private:
	ConcurrentQueue& swap_internal(ConcurrentQueue& other)
	{
		if (this == &other) {
			return *this;
		}
		
		details::swap_relaxed(producerListTail, other.producerListTail);
		details::swap_relaxed(producerCount, other.producerCount);
		details::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex);
		std::swap(initialBlockPool, other.initialBlockPool);
		std::swap(initialBlockPoolSize, other.initialBlockPoolSize);
		freeList.swap(other.freeList);
		details::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId);
		details::swap_relaxed(globalExplicitConsumerOffset, other.globalExplicitConsumerOffset);
		
		swap_implicit_producer_hashes(other);
		
		reown_producers();
		other.reown_producers();
		
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
		details::swap_relaxed(explicitProducers, other.explicitProducers);
		details::swap_relaxed(implicitProducers, other.implicitProducers);
#endif
		
		return *this;
	}
	
public:
	// Enqueues a single item (by copying it).
	// Allocates memory if required. Only fails if memory allocation fails (or implicit
	// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,
	// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
	// Thread-safe.
	inline bool enqueue(T const& item)
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;
		else return inner_enqueue<CanAlloc>(item);
	}
	
	// Enqueues a single item (by moving it, if possible).
	// Allocates memory if required. Only fails if memory allocation fails (or implicit
	// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,
	// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
	// Thread-safe.
	inline bool enqueue(T&& item)
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;
		else return inner_enqueue<CanAlloc>(std::move(item));
	}
	
	// Enqueues a single item (by copying it) using an explicit producer token.
	// Allocates memory if required. Only fails if memory allocation fails (or
	// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
	// Thread-safe.
	inline bool enqueue(producer_token_t const& token, T const& item)
	{
		return inner_enqueue<CanAlloc>(token, item);
	}
	
	// Enqueues a single item (by moving it, if possible) using an explicit producer token.
	// Allocates memory if required. Only fails if memory allocation fails (or
	// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
	// Thread-safe.
	inline bool enqueue(producer_token_t const& token, T&& item)
	{
		return inner_enqueue<CanAlloc>(token, std::move(item));
	}
	
	// Enqueues several items.
	// Allocates memory if required. Only fails if memory allocation fails (or
	// implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE
	// is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
	// Note: Use std::make_move_iterator if the elements should be moved instead of copied.
	// Thread-safe.
	template<typename It>
	bool enqueue_bulk(It itemFirst, size_t count)
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;
		else return inner_enqueue_bulk<CanAlloc>(itemFirst, count);
	}
	
	// Enqueues several items using an explicit producer token.
	// Allocates memory if required. Only fails if memory allocation fails
	// (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
	// Note: Use std::make_move_iterator if the elements should be moved
	// instead of copied.
	// Thread-safe.
	template<typename It>
	bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
	{
		return inner_enqueue_bulk<CanAlloc>(token, itemFirst, count);
	}
	
	// Enqueues a single item (by copying it).
	// Does not allocate memory. Fails if not enough room to enqueue (or implicit
	// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE
	// is 0).
	// Thread-safe.
	inline bool try_enqueue(T const& item)
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;
		else return inner_enqueue<CannotAlloc>(item);
	}
	
	// Enqueues a single item (by moving it, if possible).
	// Does not allocate memory (except for one-time implicit producer).
	// Fails if not enough room to enqueue (or implicit production is
	// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).
	// Thread-safe.
	inline bool try_enqueue(T&& item)
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;
		else return inner_enqueue<CannotAlloc>(std::move(item));
	}
	
	// Enqueues a single item (by copying it) using an explicit producer token.
	// Does not allocate memory. Fails if not enough room to enqueue.
	// Thread-safe.
	inline bool try_enqueue(producer_token_t const& token, T const& item)
	{
		return inner_enqueue<CannotAlloc>(token, item);
	}
	
	// Enqueues a single item (by moving it, if possible) using an explicit producer token.
	// Does not allocate memory. Fails if not enough room to enqueue.
	// Thread-safe.
	inline bool try_enqueue(producer_token_t const& token, T&& item)
	{
		return inner_enqueue<CannotAlloc>(token, std::move(item));
	}
	
	// Enqueues several items.
	// Does not allocate memory (except for one-time implicit producer).
	// Fails if not enough room to enqueue (or implicit production is
	// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).
	// Note: Use std::make_move_iterator if the elements should be moved
	// instead of copied.
	// Thread-safe.
	template<typename It>
	bool try_enqueue_bulk(It itemFirst, size_t count)
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false;
		else return inner_enqueue_bulk<CannotAlloc>(itemFirst, count);
	}
	
	// Enqueues several items using an explicit producer token.
	// Does not allocate memory. Fails if not enough room to enqueue.
	// Note: Use std::make_move_iterator if the elements should be moved
	// instead of copied.
	// Thread-safe.
	template<typename It>
	bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
	{
		return inner_enqueue_bulk<CannotAlloc>(token, itemFirst, count);
	}
	
	
	
	// Attempts to dequeue from the queue.
	// Returns false if all producer streams appeared empty at the time they
	// were checked (so, the queue is likely but not guaranteed to be empty).
	// Never allocates. Thread-safe.
	template<typename U>
	bool try_dequeue(U& item)
	{
		// Instead of simply trying each producer in turn (which could cause needless contention on the first
		// producer), we score them heuristically.
		size_t nonEmptyCount = 0;
		ProducerBase* best = nullptr;
		size_t bestSize = 0;
		for (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) {
			auto size = ptr->size_approx();
			if (size > 0) {
				if (size > bestSize) {
					bestSize = size;
					best = ptr;
				}
				++nonEmptyCount;
			}
		}
		
		// If there was at least one non-empty queue but it appears empty at the time
		// we try to dequeue from it, we need to make sure every queue's been tried
		if (nonEmptyCount > 0) {
			if ((details::likely)(best->dequeue(item))) {
				return true;
			}
			for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {
				if (ptr != best && ptr->dequeue(item)) {
					return true;
				}
			}
		}
		return false;
	}
	
	// Attempts to dequeue from the queue.
	// Returns false if all producer streams appeared empty at the time they
	// were checked (so, the queue is likely but not guaranteed to be empty).
	// This differs from the try_dequeue(item) method in that this one does
	// not attempt to reduce contention by interleaving the order that producer
	// streams are dequeued from. So, using this method can reduce overall throughput
	// under contention, but will give more predictable results in single-threaded
	// consumer scenarios. This is mostly only useful for internal unit tests.
	// Never allocates. Thread-safe.
	template<typename U>
	bool try_dequeue_non_interleaved(U& item)
	{
		for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {
			if (ptr->dequeue(item)) {
				return true;
			}
		}
		return false;
	}
	
	// Attempts to dequeue from the queue using an explicit consumer token.
	// Returns false if all producer streams appeared empty at the time they
	// were checked (so, the queue is likely but not guaranteed to be empty).
	// Never allocates. Thread-safe.
	template<typename U>
	bool try_dequeue(consumer_token_t& token, U& item)
	{
		// The idea is roughly as follows:
		// Every 256 items from one producer, make everyone rotate (increase the global offset) -> this means the highest efficiency consumer dictates the rotation speed of everyone else, more or less
		// If you see that the global offset has changed, you must reset your consumption counter and move to your designated place
		// If there's no items where you're supposed to be, keep moving until you find a producer with some items
		// If the global offset has not changed but you've run out of items to consume, move over from your current position until you find an producer with something in it
		
		if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) {
			if (!update_current_producer_after_rotation(token)) {
				return false;
			}
		}
		
		// If there was at least one non-empty queue but it appears empty at the time
		// we try to dequeue from it, we need to make sure every queue's been tried
		if (static_cast<ProducerBase*>(token.currentProducer)->dequeue(item)) {
			if (++token.itemsConsumedFromCurrent == EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) {
				globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed);
			}
			return true;
		}
		
		auto tail = producerListTail.load(std::memory_order_acquire);
		auto ptr = static_cast<ProducerBase*>(token.currentProducer)->next_prod();
		if (ptr == nullptr) {
			ptr = tail;
		}
		while (ptr != static_cast<ProducerBase*>(token.currentProducer)) {
			if (ptr->dequeue(item)) {
				token.currentProducer = ptr;
				token.itemsConsumedFromCurrent = 1;
				return true;
			}
			ptr = ptr->next_prod();
			if (ptr == nullptr) {
				ptr = tail;
			}
		}
		return false;
	}
	
	// Attempts to dequeue several elements from the queue.
	// Returns the number of items actually dequeued.
	// Returns 0 if all producer streams appeared empty at the time they
	// were checked (so, the queue is likely but not guaranteed to be empty).
	// Never allocates. Thread-safe.
	template<typename It>
	size_t try_dequeue_bulk(It itemFirst, size_t max)
	{
		size_t count = 0;
		for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {
			count += ptr->dequeue_bulk(itemFirst, max - count);
			if (count == max) {
				break;
			}
		}
		return count;
	}
	
	// Attempts to dequeue several elements from the queue using an explicit consumer token.
	// Returns the number of items actually dequeued.
	// Returns 0 if all producer streams appeared empty at the time they
	// were checked (so, the queue is likely but not guaranteed to be empty).
	// Never allocates. Thread-safe.
	template<typename It>
	size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)
	{
		if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) {
			if (!update_current_producer_after_rotation(token)) {
				return 0;
			}
		}
		
		size_t count = static_cast<ProducerBase*>(token.currentProducer)->dequeue_bulk(itemFirst, max);
		if (count == max) {
			if ((token.itemsConsumedFromCurrent += static_cast<std::uint32_t>(max)) >= EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) {
				globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed);
			}
			return max;
		}
		token.itemsConsumedFromCurrent += static_cast<std::uint32_t>(count);
		max -= count;
		
		auto tail = producerListTail.load(std::memory_order_acquire);
		auto ptr = static_cast<ProducerBase*>(token.currentProducer)->next_prod();
		if (ptr == nullptr) {
			ptr = tail;
		}
		while (ptr != static_cast<ProducerBase*>(token.currentProducer)) {
			auto dequeued = ptr->dequeue_bulk(itemFirst, max);
			count += dequeued;
			if (dequeued != 0) {
				token.currentProducer = ptr;
				token.itemsConsumedFromCurrent = static_cast<std::uint32_t>(dequeued);
			}
			if (dequeued == max) {
				break;
			}
			max -= dequeued;
			ptr = ptr->next_prod();
			if (ptr == nullptr) {
				ptr = tail;
			}
		}
		return count;
	}
	
	
	
	// Attempts to dequeue from a specific producer's inner queue.
	// If you happen to know which producer you want to dequeue from, this
	// is significantly faster than using the general-case try_dequeue methods.
	// Returns false if the producer's queue appeared empty at the time it
	// was checked (so, the queue is likely but not guaranteed to be empty).
	// Never allocates. Thread-safe.
	template<typename U>
	inline bool try_dequeue_from_producer(producer_token_t const& producer, U& item)
	{
		return static_cast<ExplicitProducer*>(producer.producer)->dequeue(item);
	}
	
	// Attempts to dequeue several elements from a specific producer's inner queue.
	// Returns the number of items actually dequeued.
	// If you happen to know which producer you want to dequeue from, this
	// is significantly faster than using the general-case try_dequeue methods.
	// Returns 0 if the producer's queue appeared empty at the time it
	// was checked (so, the queue is likely but not guaranteed to be empty).
	// Never allocates. Thread-safe.
	template<typename It>
	inline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, It itemFirst, size_t max)
	{
		return static_cast<ExplicitProducer*>(producer.producer)->dequeue_bulk(itemFirst, max);
	}
	
	
	// Returns an estimate of the total number of elements currently in the queue. This
	// estimate is only accurate if the queue has completely stabilized before it is called
	// (i.e. all enqueue and dequeue operations have completed and their memory effects are
	// visible on the calling thread, and no further operations start while this method is
	// being called).
	// Thread-safe.
	size_t size_approx() const
	{
		size_t size = 0;
		for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {
			size += ptr->size_approx();
		}
		return size;
	}
	
	
	// Returns true if the underlying atomic variables used by
	// the queue are lock-free (they should be on most platforms).
	// Thread-safe.
	static bool is_lock_free()
	{
		return
			details::static_is_lock_free<bool>::value == 2 &&
			details::static_is_lock_free<size_t>::value == 2 &&
			details::static_is_lock_free<std::uint32_t>::value == 2 &&
			details::static_is_lock_free<index_t>::value == 2 &&
			details::static_is_lock_free<void*>::value == 2 &&
			details::static_is_lock_free<typename details::thread_id_converter<details::thread_id_t>::thread_id_numeric_size_t>::value == 2;
	}


private:
	friend struct ProducerToken;
	friend struct ConsumerToken;
	struct ExplicitProducer;
	friend struct ExplicitProducer;
	struct ImplicitProducer;
	friend struct ImplicitProducer;
	friend class ConcurrentQueueTests;
		
	enum AllocationMode { CanAlloc, CannotAlloc };
	
	
	///////////////////////////////
	// Queue methods
	///////////////////////////////
	
	template<AllocationMode canAlloc, typename U>
	inline bool inner_enqueue(producer_token_t const& token, U&& element)
	{
		return static_cast<ExplicitProducer*>(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue<canAlloc>(std::forward<U>(element));
	}
	
	template<AllocationMode canAlloc, typename U>
	inline bool inner_enqueue(U&& element)
	{
		auto producer = get_or_add_implicit_producer();
		return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue<canAlloc>(std::forward<U>(element));
	}
	
	template<AllocationMode canAlloc, typename It>
	inline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
	{
		return static_cast<ExplicitProducer*>(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk<canAlloc>(itemFirst, count);
	}
	
	template<AllocationMode canAlloc, typename It>
	inline bool inner_enqueue_bulk(It itemFirst, size_t count)
	{
		auto producer = get_or_add_implicit_producer();
		return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk<canAlloc>(itemFirst, count);
	}
	
	inline bool update_current_producer_after_rotation(consumer_token_t& token)
	{
		// Ah, there's been a rotation, figure out where we should be!
		auto tail = producerListTail.load(std::memory_order_acquire);
		if (token.desiredProducer == nullptr && tail == nullptr) {
			return false;
		}
		auto prodCount = producerCount.load(std::memory_order_relaxed);
		auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed);
		if (token.desiredProducer == nullptr) {
			// Aha, first time we're dequeueing anything.
			// Figure out our local position
			// Note: offset is from start, not end, but we're traversing from end -- subtract from count first
			std::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount);
			token.desiredProducer = tail;
			for (std::uint32_t i = 0; i != offset; ++i) {
				token.desiredProducer = static_cast<ProducerBase*>(token.desiredProducer)->next_prod();
				if (token.desiredProducer == nullptr) {
					token.desiredProducer = tail;
				}
			}
		}
		
		std::uint32_t delta = globalOffset - token.lastKnownGlobalOffset;
		if (delta >= prodCount) {
			delta = delta % prodCount;
		}
		for (std::uint32_t i = 0; i != delta; ++i) {
			token.desiredProducer = static_cast<ProducerBase*>(token.desiredProducer)->next_prod();
			if (token.desiredProducer == nullptr) {
				token.desiredProducer = tail;
			}
		}
		
		token.lastKnownGlobalOffset = globalOffset;
		token.currentProducer = token.desiredProducer;
		token.itemsConsumedFromCurrent = 0;
		return true;
	}
	
	
	///////////////////////////
	// Free list
	///////////////////////////
	
	template <typename N>
	struct FreeListNode
	{
		FreeListNode() : freeListRefs(0), freeListNext(nullptr) { }
		
		std::atomic<std::uint32_t> freeListRefs;
		std::atomic<N*> freeListNext;
	};
	
	// A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but
	// simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly
	// speedy under low contention.
	template<typename N>		// N must inherit FreeListNode or have the same fields (and initialization of them)
	struct FreeList
	{
		FreeList() : freeListHead(nullptr) { }
		FreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); }
		void swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); }
		
		FreeList(FreeList const&) MOODYCAMEL_DELETE_FUNCTION;
		FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION;
		
		inline void add(N* node)
		{
#ifdef MCDBGQ_NOLOCKFREE_FREELIST
			debug::DebugLock lock(mutex);
#endif		
			// We know that the should-be-on-freelist bit is 0 at this point, so it's safe to
			// set it using a fetch_add
			if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) {
				// Oh look! We were the last ones referencing this node, and we know
				// we want to add it to the free list, so let's do it!
		 		add_knowing_refcount_is_zero(node);
			}
		}
		
		inline N* try_get()
		{
#ifdef MCDBGQ_NOLOCKFREE_FREELIST
			debug::DebugLock lock(mutex);
#endif		
			auto head = freeListHead.load(std::memory_order_acquire);
			while (head != nullptr) {
				auto prevHead = head;
				auto refs = head->freeListRefs.load(std::memory_order_relaxed);
				if ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) {
					head = freeListHead.load(std::memory_order_acquire);
					continue;
				}
				
				// Good, reference count has been incremented (it wasn't at zero), which means we can read the
				// next and not worry about it changing between now and the time we do the CAS
				auto next = head->freeListNext.load(std::memory_order_relaxed);
				if (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) {
					// Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no
					// matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on).
					assert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0);
					
					// Decrease refcount twice, once for our ref, and once for the list's ref
					head->freeListRefs.fetch_sub(2, std::memory_order_release);
					return head;
				}
				
				// OK, the head must have changed on us, but we still need to decrease the refcount we increased.
				// Note that we don't need to release any memory effects, but we do need to ensure that the reference
				// count decrement happens-after the CAS on the head.
				refs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel);
				if (refs == SHOULD_BE_ON_FREELIST + 1) {
					add_knowing_refcount_is_zero(prevHead);
				}
			}
			
			return nullptr;
		}
		
		// Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes)
		N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); }
		
	private:
		inline void add_knowing_refcount_is_zero(N* node)
		{
			// Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run
			// only one copy of this method per node at a time, i.e. the single thread case), then we know
			// we can safely change the next pointer of the node; however, once the refcount is back above
			// zero, then other threads could increase it (happens under heavy contention, when the refcount
			// goes to zero in between a load and a refcount increment of a node in try_get, then back up to
			// something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS
			// to add the node to the actual list fails, decrease the refcount and leave the add operation to
			// the next thread who puts the refcount back at zero (which could be us, hence the loop).
			auto head = freeListHead.load(std::memory_order_relaxed);
			while (true) {
				node->freeListNext.store(head, std::memory_order_relaxed);
				node->freeListRefs.store(1, std::memory_order_release);
				if (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) {
					// Hmm, the add failed, but we can only try again when the refcount goes back to zero
					if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) {
						continue;
					}
				}
				return;
			}
		}
		
	private:
		// Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention)
		std::atomic<N*> freeListHead;
	
	static const std::uint32_t REFS_MASK = 0x7FFFFFFF;
	static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000;
		
#ifdef MCDBGQ_NOLOCKFREE_FREELIST
		debug::DebugMutex mutex;
#endif
	};
	
	
	///////////////////////////
	// Block
	///////////////////////////
	
	enum InnerQueueContext { implicit_context = 0, explicit_context = 1 };
	
	struct Block
	{
		Block()
			: next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), shouldBeOnFreeList(false), dynamicallyAllocated(true)
		{
#ifdef MCDBGQ_TRACKMEM
			owner = nullptr;
#endif
		}
		
		template<InnerQueueContext context>
		inline bool is_empty() const
		{
			MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {
				// Check flags
				for (size_t i = 0; i < BLOCK_SIZE; ++i) {
					if (!emptyFlags[i].load(std::memory_order_relaxed)) {
						return false;
					}
				}
				
				// Aha, empty; make sure we have all other memory effects that happened before the empty flags were set
				std::atomic_thread_fence(std::memory_order_acquire);
				return true;
			}
			else {
				// Check counter
				if (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) {
					std::atomic_thread_fence(std::memory_order_acquire);
					return true;
				}
				assert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE);
				return false;
			}
		}
		
		// Returns true if the block is now empty (does not apply in explicit context)
		template<InnerQueueContext context>
		inline bool set_empty(MOODYCAMEL_MAYBE_UNUSED index_t i)
		{
			MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {
				// Set flag
				assert(!emptyFlags[BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1))].load(std::memory_order_relaxed));
				emptyFlags[BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1))].store(true, std::memory_order_release);
				return false;
			}
			else {
				// Increment counter
				auto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release);
				assert(prevVal < BLOCK_SIZE);
				return prevVal == BLOCK_SIZE - 1;
			}
		}
		
		// Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0).
		// Returns true if the block is now empty (does not apply in explicit context).
		template<InnerQueueContext context>
		inline bool set_many_empty(MOODYCAMEL_MAYBE_UNUSED index_t i, size_t count)
		{
			MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {
				// Set flags
				std::atomic_thread_fence(std::memory_order_release);
				i = BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1)) - count + 1;
				for (size_t j = 0; j != count; ++j) {
					assert(!emptyFlags[i + j].load(std::memory_order_relaxed));
					emptyFlags[i + j].store(true, std::memory_order_relaxed);
				}
				return false;
			}
			else {
				// Increment counter
				auto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release);
				assert(prevVal + count <= BLOCK_SIZE);
				return prevVal + count == BLOCK_SIZE;
			}
		}
		
		template<InnerQueueContext context>
		inline void set_all_empty()
		{
			MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {
				// Set all flags
				for (size_t i = 0; i != BLOCK_SIZE; ++i) {
					emptyFlags[i].store(true, std::memory_order_relaxed);
				}
			}
			else {
				// Reset counter
				elementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed);
			}
		}
		
		template<InnerQueueContext context>
		inline void reset_empty()
		{
			MOODYCAMEL_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {
				// Reset flags
				for (size_t i = 0; i != BLOCK_SIZE; ++i) {
					emptyFlags[i].store(false, std::memory_order_relaxed);
				}
			}
			else {
				// Reset counter
				elementsCompletelyDequeued.store(0, std::memory_order_relaxed);
			}
		}
		
		inline T* operator[](index_t idx) MOODYCAMEL_NOEXCEPT { return static_cast<T*>(static_cast<void*>(elements)) + static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); }
		inline T const* operator[](index_t idx) const MOODYCAMEL_NOEXCEPT { return static_cast<T const*>(static_cast<void const*>(elements)) + static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); }
		
	private:
		static_assert(std::alignment_of<T>::value <= sizeof(T), "The queue does not support types with an alignment greater than their size at this time");
		MOODYCAMEL_ALIGNAS(MOODYCAMEL_ALIGNOF(T)) char elements[sizeof(T) * BLOCK_SIZE];
	public:
		Block* next;
		std::atomic<size_t> elementsCompletelyDequeued;
		std::atomic<bool> emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1];
	public:
		std::atomic<std::uint32_t> freeListRefs;
		std::atomic<Block*> freeListNext;
		std::atomic<bool> shouldBeOnFreeList;
		bool dynamicallyAllocated;		// Perhaps a better name for this would be 'isNotPartOfInitialBlockPool'
		
#ifdef MCDBGQ_TRACKMEM
		void* owner;
#endif
	};
	static_assert(std::alignment_of<Block>::value >= std::alignment_of<T>::value, "Internal error: Blocks must be at least as aligned as the type they are wrapping");


#ifdef MCDBGQ_TRACKMEM
public:
	struct MemStats;
private:
#endif
	
	///////////////////////////
	// Producer base
	///////////////////////////
	
	struct ProducerBase : public details::ConcurrentQueueProducerTypelessBase
	{
		ProducerBase(ConcurrentQueue* parent_, bool isExplicit_) :
			tailIndex(0),
			headIndex(0),
			dequeueOptimisticCount(0),
			dequeueOvercommit(0),
			tailBlock(nullptr),
			isExplicit(isExplicit_),
			parent(parent_)
		{
		}
		
		virtual ~ProducerBase() { };
		
		template<typename U>
		inline bool dequeue(U& element)
		{
			if (isExplicit) {
				return static_cast<ExplicitProducer*>(this)->dequeue(element);
			}
			else {
				return static_cast<ImplicitProducer*>(this)->dequeue(element);
			}
		}
		
		template<typename It>
		inline size_t dequeue_bulk(It& itemFirst, size_t max)
		{
			if (isExplicit) {
				return static_cast<ExplicitProducer*>(this)->dequeue_bulk(itemFirst, max);
			}
			else {
				return static_cast<ImplicitProducer*>(this)->dequeue_bulk(itemFirst, max);
			}
		}
		
		inline ProducerBase* next_prod() const { return static_cast<ProducerBase*>(next); }
		
		inline size_t size_approx() const
		{
			auto tail = tailIndex.load(std::memory_order_relaxed);
			auto head = headIndex.load(std::memory_order_relaxed);
			return details::circular_less_than(head, tail) ? static_cast<size_t>(tail - head) : 0;
		}
		
		inline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); }
	protected:
		std::atomic<index_t> tailIndex;		// Where to enqueue to next
		std::atomic<index_t> headIndex;		// Where to dequeue from next
		
		std::atomic<index_t> dequeueOptimisticCount;
		std::atomic<index_t> dequeueOvercommit;
		
		Block* tailBlock;
		
	public:
		bool isExplicit;
		ConcurrentQueue* parent;
		
	protected:
#ifdef MCDBGQ_TRACKMEM
		friend struct MemStats;
#endif
	};
	
	
	///////////////////////////
	// Explicit queue
	///////////////////////////
		
	struct ExplicitProducer : public ProducerBase
	{
		explicit ExplicitProducer(ConcurrentQueue* parent_) :
			ProducerBase(parent_, true),
			blockIndex(nullptr),
			pr_blockIndexSlotsUsed(0),
			pr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1),
			pr_blockIndexFront(0),
			pr_blockIndexEntries(nullptr),
			pr_blockIndexRaw(nullptr)
		{
			size_t poolBasedIndexSize = details::ceil_to_pow_2(parent_->initialBlockPoolSize) >> 1;
			if (poolBasedIndexSize > pr_blockIndexSize) {
				pr_blockIndexSize = poolBasedIndexSize;
			}
			
			new_block_index(0);		// This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE
		}
		
		~ExplicitProducer()
		{
			// Destruct any elements not yet dequeued.
			// Since we're in the destructor, we can assume all elements
			// are either completely dequeued or completely not (no halfways).
			if (this->tailBlock != nullptr) {		// Note this means there must be a block index too
				// First find the block that's partially dequeued, if any
				Block* halfDequeuedBlock = nullptr;
				if ((this->headIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1)) != 0) {
					// The head's not on a block boundary, meaning a block somewhere is partially dequeued
					// (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary)
					size_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1);
					while (details::circular_less_than<index_t>(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) {
						i = (i + 1) & (pr_blockIndexSize - 1);
					}
					assert(details::circular_less_than<index_t>(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed)));
					halfDequeuedBlock = pr_blockIndexEntries[i].block;
				}
				
				// Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration)
				auto block = this->tailBlock;
				do {
					block = block->next;
					if (block->ConcurrentQueue::Block::template is_empty<explicit_context>()) {
						continue;
					}
					
					size_t i = 0;	// Offset into block
					if (block == halfDequeuedBlock) {
						i = static_cast<size_t>(this->headIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1));
					}
					
					// Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index
					auto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast<size_t>(this->tailIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1));
					while (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) {
						(*block)[i++]->~T();
					}
				} while (block != this->tailBlock);
			}
			
			// Destroy all blocks that we own
			if (this->tailBlock != nullptr) {
				auto block = this->tailBlock;
				do {
					auto nextBlock = block->next;
					if (block->dynamicallyAllocated) {
						destroy(block);
					}
					else {
						this->parent->add_block_to_free_list(block);
					}
					block = nextBlock;
				} while (block != this->tailBlock);
			}
			
			// Destroy the block indices
			auto header = static_cast<BlockIndexHeader*>(pr_blockIndexRaw);
			while (header != nullptr) {
				auto prev = static_cast<BlockIndexHeader*>(header->prev);
				header->~BlockIndexHeader();
				(Traits::free)(header);
				header = prev;
			}
		}
		
		template<AllocationMode allocMode, typename U>
		inline bool enqueue(U&& element)
		{
			index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed);
			index_t newTailIndex = 1 + currentTailIndex;
			if ((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {
				// We reached the end of a block, start a new one
				auto startBlock = this->tailBlock;
				auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed;
				if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty<explicit_context>()) {
					// We can re-use the block ahead of us, it's empty!					
					this->tailBlock = this->tailBlock->next;
					this->tailBlock->ConcurrentQueue::Block::template reset_empty<explicit_context>();
					
					// We'll put the block on the block index (guaranteed to be room since we're conceptually removing the
					// last block from it first -- except instead of removing then adding, we can just overwrite).
					// Note that there must be a valid block index here, since even if allocation failed in the ctor,
					// it would have been re-attempted when adding the first block to the queue; since there is such
					// a block, a block index must have been successfully allocated.
				}
				else {
					// Whatever head value we see here is >= the last value we saw here (relatively),
					// and <= its current value. Since we have the most recent tail, the head must be
					// <= to it.
					auto head = this->headIndex.load(std::memory_order_relaxed);
					assert(!details::circular_less_than<index_t>(currentTailIndex, head));
					if (!details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE)
						|| (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) {
						// We can't enqueue in another block because there's not enough leeway -- the
						// tail could surpass the head by the time the block fills up! (Or we'll exceed
						// the size limit, if the second part of the condition was true.)
						return false;
					}
					// We're going to need a new block; check that the block index has room
					if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) {
						// Hmm, the circular block index is already full -- we'll need
						// to allocate a new index. Note pr_blockIndexRaw can only be nullptr if
						// the initial allocation failed in the constructor.
						
						MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {
							return false;
						}
						else if (!new_block_index(pr_blockIndexSlotsUsed)) {
							return false;
						}
					}
					
					// Insert a new block in the circular linked list
					auto newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>();
					if (newBlock == nullptr) {
						return false;
					}
#ifdef MCDBGQ_TRACKMEM
					newBlock->owner = this;
#endif
					newBlock->ConcurrentQueue::Block::template reset_empty<explicit_context>();
					if (this->tailBlock == nullptr) {
						newBlock->next = newBlock;
					}
					else {
						newBlock->next = this->tailBlock->next;
						this->tailBlock->next = newBlock;
					}
					this->tailBlock = newBlock;
					++pr_blockIndexSlotsUsed;
				}

				if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
					// The constructor may throw. We want the element not to appear in the queue in
					// that case (without corrupting the queue):
					MOODYCAMEL_TRY {
						new ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element));
					}
					MOODYCAMEL_CATCH (...) {
						// Revert change to the current block, but leave the new block available
						// for next time
						pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;
						this->tailBlock = startBlock == nullptr ? this->tailBlock : startBlock;
						MOODYCAMEL_RETHROW;
					}
				}
				else {
					(void)startBlock;
					(void)originalBlockIndexSlotsUsed;
				}
				
				// Add block to block index
				auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];
				entry.base = currentTailIndex;
				entry.block = this->tailBlock;
				blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release);
				pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);
				
				if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
					this->tailIndex.store(newTailIndex, std::memory_order_release);
					return true;
				}
			}
			
			// Enqueue
			new ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element));
			
			this->tailIndex.store(newTailIndex, std::memory_order_release);
			return true;
		}
		
		template<typename U>
		bool dequeue(U& element)
		{
			auto tail = this->tailIndex.load(std::memory_order_relaxed);
			auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);
			if (details::circular_less_than<index_t>(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) {
				// Might be something to dequeue, let's give it a try
				
				// Note that this if is purely for performance purposes in the common case when the queue is
				// empty and the values are eventually consistent -- we may enter here spuriously.
				
				// Note that whatever the values of overcommit and tail are, they are not going to change (unless we
				// change them) and must be the same value at this point (inside the if) as when the if condition was
				// evaluated.

				// We insert an acquire fence here to synchronize-with the release upon incrementing dequeueOvercommit below.
				// This ensures that whatever the value we got loaded into overcommit, the load of dequeueOptisticCount in
				// the fetch_add below will result in a value at least as recent as that (and therefore at least as large).
				// Note that I believe a compiler (signal) fence here would be sufficient due to the nature of fetch_add (all
				// read-modify-write operations are guaranteed to work on the latest value in the modification order), but
				// unfortunately that can't be shown to be correct using only the C++11 standard.
				// See http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case
				std::atomic_thread_fence(std::memory_order_acquire);
				
				// Increment optimistic counter, then check if it went over the boundary
				auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed);
				
				// Note that since dequeueOvercommit must be <= dequeueOptimisticCount (because dequeueOvercommit is only ever
				// incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now
				// have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon
				// incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount.
				// However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently)
				// overflow; in such a case, though, the logic still holds since the difference between the two is maintained.
				
				// Note that we reload tail here in case it changed; it will be the same value as before or greater, since
				// this load is sequenced after (happens after) the earlier load above. This is supported by read-read
				// coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order
				tail = this->tailIndex.load(std::memory_order_acquire);
				if ((details::likely)(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {
					// Guaranteed to be at least one element to dequeue!
					
					// Get the index. Note that since there's guaranteed to be at least one element, this
					// will never exceed tail. We need to do an acquire-release fence here since it's possible
					// that whatever condition got us to this point was for an earlier enqueued element (that
					// we already see the memory effects for), but that by the time we increment somebody else
					// has incremented it, and we need to see the memory effects for *that* element, which is
					// in such a case is necessarily visible on the thread that incremented it in the first
					// place with the more current condition (they must have acquired a tail that is at least
					// as recent).
					auto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel);
					
					
					// Determine which block the element is in
					
					auto localBlockIndex = blockIndex.load(std::memory_order_acquire);
					auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire);
					
					// We need to be careful here about subtracting and dividing because of index wrap-around.
					// When an index wraps, we need to preserve the sign of the offset when dividing it by the
					// block size (in order to get a correct signed block count offset in all cases):
					auto headBase = localBlockIndex->entries[localBlockIndexHead].base;
					auto blockBaseIndex = index & ~static_cast<index_t>(BLOCK_SIZE - 1);
					auto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(blockBaseIndex - headBase) / BLOCK_SIZE);
					auto block = localBlockIndex->entries[(localBlockIndexHead + offset) & (localBlockIndex->size - 1)].block;
					
					// Dequeue
					auto& el = *((*block)[index]);
					if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) {
						// Make sure the element is still fully dequeued and destroyed even if the assignment
						// throws
						struct Guard {
							Block* block;
							index_t index;
							
							~Guard()
							{
								(*block)[index]->~T();
								block->ConcurrentQueue::Block::template set_empty<explicit_context>(index);
							}
						} guard = { block, index };

						element = std::move(el); // NOLINT
					}
					else {
						element = std::move(el); // NOLINT
						el.~T(); // NOLINT
						block->ConcurrentQueue::Block::template set_empty<explicit_context>(index);
					}
					
					return true;
				}
				else {
					// Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent
					this->dequeueOvercommit.fetch_add(1, std::memory_order_release);		// Release so that the fetch_add on dequeueOptimisticCount is guaranteed to happen before this write
				}
			}
		
			return false;
		}
		
		template<AllocationMode allocMode, typename It>
		bool enqueue_bulk(It itemFirst, size_t count)
		{
			// First, we need to make sure we have enough room to enqueue all of the elements;
			// this means pre-allocating blocks and putting them in the block index (but only if
			// all the allocations succeeded).
			index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed);
			auto startBlock = this->tailBlock;
			auto originalBlockIndexFront = pr_blockIndexFront;
			auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed;
			
			Block* firstAllocatedBlock = nullptr;
			
			// Figure out how many blocks we'll need to allocate, and do so
			size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1));
			index_t currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);
			if (blockBaseDiff > 0) {
				// Allocate as many blocks as possible from ahead
				while (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty<explicit_context>()) {
					blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);
					currentTailIndex += static_cast<index_t>(BLOCK_SIZE);
					
					this->tailBlock = this->tailBlock->next;
					firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock;
					
					auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];
					entry.base = currentTailIndex;
					entry.block = this->tailBlock;
					pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);
				}
				
				// Now allocate as many blocks as necessary from the block pool
				while (blockBaseDiff > 0) {
					blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);
					currentTailIndex += static_cast<index_t>(BLOCK_SIZE);
					
					auto head = this->headIndex.load(std::memory_order_relaxed);
					assert(!details::circular_less_than<index_t>(currentTailIndex, head));
					bool full = !details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head));
					if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) {
						MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {
							// Failed to allocate, undo changes (but keep injected blocks)
							pr_blockIndexFront = originalBlockIndexFront;
							pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;
							this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;
							return false;
						}
						else if (full || !new_block_index(originalBlockIndexSlotsUsed)) {
							// Failed to allocate, undo changes (but keep injected blocks)
							pr_blockIndexFront = originalBlockIndexFront;
							pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;
							this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;
							return false;
						}
						
						// pr_blockIndexFront is updated inside new_block_index, so we need to
						// update our fallback value too (since we keep the new index even if we
						// later fail)
						originalBlockIndexFront = originalBlockIndexSlotsUsed;
					}
					
					// Insert a new block in the circular linked list
					auto newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>();
					if (newBlock == nullptr) {
						pr_blockIndexFront = originalBlockIndexFront;
						pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;
						this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;
						return false;
					}
					
#ifdef MCDBGQ_TRACKMEM
					newBlock->owner = this;
#endif
					newBlock->ConcurrentQueue::Block::template set_all_empty<explicit_context>();
					if (this->tailBlock == nullptr) {
						newBlock->next = newBlock;
					}
					else {
						newBlock->next = this->tailBlock->next;
						this->tailBlock->next = newBlock;
					}
					this->tailBlock = newBlock;
					firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock;
					
					++pr_blockIndexSlotsUsed;
					
					auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];
					entry.base = currentTailIndex;
					entry.block = this->tailBlock;
					pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);
				}
				
				// Excellent, all allocations succeeded. Reset each block's emptiness before we fill them up, and
				// publish the new block index front
				auto block = firstAllocatedBlock;
				while (true) {
					block->ConcurrentQueue::Block::template reset_empty<explicit_context>();
					if (block == this->tailBlock) {
						break;
					}
					block = block->next;
				}
				
				if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) {
					blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release);
				}
			}
			
			// Enqueue, one block at a time
			index_t newTailIndex = startTailIndex + static_cast<index_t>(count);
			currentTailIndex = startTailIndex;
			auto endBlock = this->tailBlock;
			this->tailBlock = startBlock;
			assert((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0);
			if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) {
				this->tailBlock = firstAllocatedBlock;
			}
			while (true) {
				auto stopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
				if (details::circular_less_than<index_t>(newTailIndex, stopIndex)) {
					stopIndex = newTailIndex;
				}
				if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) {
					while (currentTailIndex != stopIndex) {
						new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++);
					}
				}
				else {
					MOODYCAMEL_TRY {
						while (currentTailIndex != stopIndex) {
							// Must use copy constructor even if move constructor is available
							// because we may have to revert if there's an exception.
							// Sorry about the horrible templated next line, but it was the only way
							// to disable moving *at compile time*, which is important because a type
							// may only define a (noexcept) move constructor, and so calls to the
							// cctor will not compile, even if they are in an if branch that will never
							// be executed
							new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));
							++currentTailIndex;
							++itemFirst;
						}
					}
					MOODYCAMEL_CATCH (...) {
						// Oh dear, an exception's been thrown -- destroy the elements that
						// were enqueued so far and revert the entire bulk operation (we'll keep
						// any allocated blocks in our linked list for later, though).
						auto constructedStopIndex = currentTailIndex;
						auto lastBlockEnqueued = this->tailBlock;
						
						pr_blockIndexFront = originalBlockIndexFront;
						pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed;
						this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock;
						
						if (!details::is_trivially_destructible<T>::value) {
							auto block = startBlock;
							if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {
								block = firstAllocatedBlock;
							}
							currentTailIndex = startTailIndex;
							while (true) {
								stopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
								if (details::circular_less_than<index_t>(constructedStopIndex, stopIndex)) {
									stopIndex = constructedStopIndex;
								}
								while (currentTailIndex != stopIndex) {
									(*block)[currentTailIndex++]->~T();
								}
								if (block == lastBlockEnqueued) {
									break;
								}
								block = block->next;
							}
						}
						MOODYCAMEL_RETHROW;
					}
				}
				
				if (this->tailBlock == endBlock) {
					assert(currentTailIndex == newTailIndex);
					break;
				}
				this->tailBlock = this->tailBlock->next;
			}
			
			if (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst))) && firstAllocatedBlock != nullptr) {
				blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release);
			}
			
			this->tailIndex.store(newTailIndex, std::memory_order_release);
			return true;
		}
		
		template<typename It>
		size_t dequeue_bulk(It& itemFirst, size_t max)
		{
			auto tail = this->tailIndex.load(std::memory_order_relaxed);
			auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);
			auto desiredCount = static_cast<size_t>(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit));
			if (details::circular_less_than<size_t>(0, desiredCount)) {
				desiredCount = desiredCount < max ? desiredCount : max;
				std::atomic_thread_fence(std::memory_order_acquire);
				
				auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);;
				
				tail = this->tailIndex.load(std::memory_order_acquire);
				auto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit));
				if (details::circular_less_than<size_t>(0, actualCount)) {
					actualCount = desiredCount < actualCount ? desiredCount : actualCount;
					if (actualCount < desiredCount) {
						this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release);
					}
					
					// Get the first index. Note that since there's guaranteed to be at least actualCount elements, this
					// will never exceed tail.
					auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel);
					
					// Determine which block the first element is in
					auto localBlockIndex = blockIndex.load(std::memory_order_acquire);
					auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire);
					
					auto headBase = localBlockIndex->entries[localBlockIndexHead].base;
					auto firstBlockBaseIndex = firstIndex & ~static_cast<index_t>(BLOCK_SIZE - 1);
					auto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(firstBlockBaseIndex - headBase) / BLOCK_SIZE);
					auto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1);
					
					// Iterate the blocks and dequeue
					auto index = firstIndex;
					do {
						auto firstIndexInBlock = index;
						auto endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
						endIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;
						auto block = localBlockIndex->entries[indexIndex].block;
						if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) {
							while (index != endIndex) {
								auto& el = *((*block)[index]);
								*itemFirst++ = std::move(el);
								el.~T();
								++index;
							}
						}
						else {
							MOODYCAMEL_TRY {
								while (index != endIndex) {
									auto& el = *((*block)[index]);
									*itemFirst = std::move(el);
									++itemFirst;
									el.~T();
									++index;
								}
							}
							MOODYCAMEL_CATCH (...) {
								// It's too late to revert the dequeue, but we can make sure that all
								// the dequeued objects are properly destroyed and the block index
								// (and empty count) are properly updated before we propagate the exception
								do {
									block = localBlockIndex->entries[indexIndex].block;
									while (index != endIndex) {
										(*block)[index++]->~T();
									}
									block->ConcurrentQueue::Block::template set_many_empty<explicit_context>(firstIndexInBlock, static_cast<size_t>(endIndex - firstIndexInBlock));
									indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1);
									
									firstIndexInBlock = index;
									endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
									endIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;
								} while (index != firstIndex + actualCount);
								
								MOODYCAMEL_RETHROW;
							}
						}
						block->ConcurrentQueue::Block::template set_many_empty<explicit_context>(firstIndexInBlock, static_cast<size_t>(endIndex - firstIndexInBlock));
						indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1);
					} while (index != firstIndex + actualCount);
					
					return actualCount;
				}
				else {
					// Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent
					this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release);
				}
			}
			
			return 0;
		}
		
	private:
		struct BlockIndexEntry
		{
			index_t base;
			Block* block;
		};
		
		struct BlockIndexHeader
		{
			size_t size;
			std::atomic<size_t> front;		// Current slot (not next, like pr_blockIndexFront)
			BlockIndexEntry* entries;
			void* prev;
		};
		
		
		bool new_block_index(size_t numberOfFilledSlotsToExpose)
		{
			auto prevBlockSizeMask = pr_blockIndexSize - 1;
			
			// Create the new block
			pr_blockIndexSize <<= 1;
			auto newRawPtr = static_cast<char*>((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of<BlockIndexEntry>::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize));
			if (newRawPtr == nullptr) {
				pr_blockIndexSize >>= 1;		// Reset to allow graceful retry
				return false;
			}
			
			auto newBlockIndexEntries = reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>(newRawPtr + sizeof(BlockIndexHeader)));
			
			// Copy in all the old indices, if any
			size_t j = 0;
			if (pr_blockIndexSlotsUsed != 0) {
				auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask;
				do {
					newBlockIndexEntries[j++] = pr_blockIndexEntries[i];
					i = (i + 1) & prevBlockSizeMask;
				} while (i != pr_blockIndexFront);
			}
			
			// Update everything
			auto header = new (newRawPtr) BlockIndexHeader;
			header->size = pr_blockIndexSize;
			header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed);
			header->entries = newBlockIndexEntries;
			header->prev = pr_blockIndexRaw;		// we link the new block to the old one so we can free it later
			
			pr_blockIndexFront = j;
			pr_blockIndexEntries = newBlockIndexEntries;
			pr_blockIndexRaw = newRawPtr;
			blockIndex.store(header, std::memory_order_release);
			
			return true;
		}
		
	private:
		std::atomic<BlockIndexHeader*> blockIndex;
		
		// To be used by producer only -- consumer must use the ones in referenced by blockIndex
		size_t pr_blockIndexSlotsUsed;
		size_t pr_blockIndexSize;
		size_t pr_blockIndexFront;		// Next slot (not current)
		BlockIndexEntry* pr_blockIndexEntries;
		void* pr_blockIndexRaw;
		
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
	public:
		ExplicitProducer* nextExplicitProducer;
	private:
#endif
		
#ifdef MCDBGQ_TRACKMEM
		friend struct MemStats;
#endif
	};
	
	
	//////////////////////////////////
	// Implicit queue
	//////////////////////////////////
	
	struct ImplicitProducer : public ProducerBase
	{			
		ImplicitProducer(ConcurrentQueue* parent_) :
			ProducerBase(parent_, false),
			nextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE),
			blockIndex(nullptr)
		{
			new_block_index();
		}
		
		~ImplicitProducer()
		{
			// Note that since we're in the destructor we can assume that all enqueue/dequeue operations
			// completed already; this means that all undequeued elements are placed contiguously across
			// contiguous blocks, and that only the first and last remaining blocks can be only partially
			// empty (all other remaining blocks must be completely full).
			
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
			// Unregister ourselves for thread termination notification
			if (!this->inactive.load(std::memory_order_relaxed)) {
				details::ThreadExitNotifier::unsubscribe(&threadExitListener);
			}
#endif
			
			// Destroy all remaining elements!
			auto tail = this->tailIndex.load(std::memory_order_relaxed);
			auto index = this->headIndex.load(std::memory_order_relaxed);
			Block* block = nullptr;
			assert(index == tail || details::circular_less_than(index, tail));
			bool forceFreeLastBlock = index != tail;		// If we enter the loop, then the last (tail) block will not be freed
			while (index != tail) {
				if ((index & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 || block == nullptr) {
					if (block != nullptr) {
						// Free the old block
						this->parent->add_block_to_free_list(block);
					}
					
					block = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed);
				}
				
				((*block)[index])->~T();
				++index;
			}
			// Even if the queue is empty, there's still one block that's not on the free list
			// (unless the head index reached the end of it, in which case the tail will be poised
			// to create a new block).
			if (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast<index_t>(BLOCK_SIZE - 1)) != 0)) {
				this->parent->add_block_to_free_list(this->tailBlock);
			}
			
			// Destroy block index
			auto localBlockIndex = blockIndex.load(std::memory_order_relaxed);
			if (localBlockIndex != nullptr) {
				for (size_t i = 0; i != localBlockIndex->capacity; ++i) {
					localBlockIndex->index[i]->~BlockIndexEntry();
				}
				do {
					auto prev = localBlockIndex->prev;
					localBlockIndex->~BlockIndexHeader();
					(Traits::free)(localBlockIndex);
					localBlockIndex = prev;
				} while (localBlockIndex != nullptr);
			}
		}
		
		template<AllocationMode allocMode, typename U>
		inline bool enqueue(U&& element)
		{
			index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed);
			index_t newTailIndex = 1 + currentTailIndex;
			if ((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {
				// We reached the end of a block, start a new one
				auto head = this->headIndex.load(std::memory_order_relaxed);
				assert(!details::circular_less_than<index_t>(currentTailIndex, head));
				if (!details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) {
					return false;
				}
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
				debug::DebugLock lock(mutex);
#endif
				// Find out where we'll be inserting this block in the block index
				BlockIndexEntry* idxEntry;
				if (!insert_block_index_entry<allocMode>(idxEntry, currentTailIndex)) {
					return false;
				}
				
				// Get ahold of a new block
				auto newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>();
				if (newBlock == nullptr) {
					rewind_block_index_tail();
					idxEntry->value.store(nullptr, std::memory_order_relaxed);
					return false;
				}
#ifdef MCDBGQ_TRACKMEM
				newBlock->owner = this;
#endif
				newBlock->ConcurrentQueue::Block::template reset_empty<implicit_context>();
				
				if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
					// May throw, try to insert now before we publish the fact that we have this new block
					MOODYCAMEL_TRY {
						new ((*newBlock)[currentTailIndex]) T(std::forward<U>(element));
					}
					MOODYCAMEL_CATCH (...) {
						rewind_block_index_tail();
						idxEntry->value.store(nullptr, std::memory_order_relaxed);
						this->parent->add_block_to_free_list(newBlock);
						MOODYCAMEL_RETHROW;
					}
				}
				
				// Insert the new block into the index
				idxEntry->value.store(newBlock, std::memory_order_relaxed);
				
				this->tailBlock = newBlock;
				
				if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
					this->tailIndex.store(newTailIndex, std::memory_order_release);
					return true;
				}
			}
			
			// Enqueue
			new ((*this->tailBlock)[currentTailIndex]) T(std::forward<U>(element));
			
			this->tailIndex.store(newTailIndex, std::memory_order_release);
			return true;
		}
		
		template<typename U>
		bool dequeue(U& element)
		{
			// See ExplicitProducer::dequeue for rationale and explanation
			index_t tail = this->tailIndex.load(std::memory_order_relaxed);
			index_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);
			if (details::circular_less_than<index_t>(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) {
				std::atomic_thread_fence(std::memory_order_acquire);
				
				index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed);
				tail = this->tailIndex.load(std::memory_order_acquire);
				if ((details::likely)(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {
					index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel);
					
					// Determine which block the element is in
					auto entry = get_block_index_entry_for_index(index);
					
					// Dequeue
					auto block = entry->value.load(std::memory_order_relaxed);
					auto& el = *((*block)[index]);
					
					if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) {
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
						// Note: Acquiring the mutex with every dequeue instead of only when a block
						// is released is very sub-optimal, but it is, after all, purely debug code.
						debug::DebugLock lock(producer->mutex);
#endif
						struct Guard {
							Block* block;
							index_t index;
							BlockIndexEntry* entry;
							ConcurrentQueue* parent;
							
							~Guard()
							{
								(*block)[index]->~T();
								if (block->ConcurrentQueue::Block::template set_empty<implicit_context>(index)) {
									entry->value.store(nullptr, std::memory_order_relaxed);
									parent->add_block_to_free_list(block);
								}
							}
						} guard = { block, index, entry, this->parent };

						element = std::move(el); // NOLINT
					}
					else {
						element = std::move(el); // NOLINT
						el.~T(); // NOLINT

						if (block->ConcurrentQueue::Block::template set_empty<implicit_context>(index)) {
							{
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
								debug::DebugLock lock(mutex);
#endif
								// Add the block back into the global free pool (and remove from block index)
								entry->value.store(nullptr, std::memory_order_relaxed);
							}
							this->parent->add_block_to_free_list(block);		// releases the above store
						}
					}
					
					return true;
				}
				else {
					this->dequeueOvercommit.fetch_add(1, std::memory_order_release);
				}
			}
		
			return false;
		}
		
		template<AllocationMode allocMode, typename It>
		bool enqueue_bulk(It itemFirst, size_t count)
		{
			// First, we need to make sure we have enough room to enqueue all of the elements;
			// this means pre-allocating blocks and putting them in the block index (but only if
			// all the allocations succeeded).
			
			// Note that the tailBlock we start off with may not be owned by us any more;
			// this happens if it was filled up exactly to the top (setting tailIndex to
			// the first index of the next block which is not yet allocated), then dequeued
			// completely (putting it on the free list) before we enqueue again.
			
			index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed);
			auto startBlock = this->tailBlock;
			Block* firstAllocatedBlock = nullptr;
			auto endBlock = this->tailBlock;
			
			// Figure out how many blocks we'll need to allocate, and do so
			size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1));
			index_t currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);
			if (blockBaseDiff > 0) {
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
				debug::DebugLock lock(mutex);
#endif
				do {
					blockBaseDiff -= static_cast<index_t>(BLOCK_SIZE);
					currentTailIndex += static_cast<index_t>(BLOCK_SIZE);
					
					// Find out where we'll be inserting this block in the block index
					BlockIndexEntry* idxEntry = nullptr;  // initialization here unnecessary but compiler can't always tell
					Block* newBlock;
					bool indexInserted = false;
					auto head = this->headIndex.load(std::memory_order_relaxed);
					assert(!details::circular_less_than<index_t>(currentTailIndex, head));
					bool full = !details::circular_less_than<index_t>(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max<size_t>::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head));
					if (full || !(indexInserted = insert_block_index_entry<allocMode>(idxEntry, currentTailIndex)) || (newBlock = this->parent->ConcurrentQueue::template requisition_block<allocMode>()) == nullptr) {
						// Index allocation or block allocation failed; revert any other allocations
						// and index insertions done so far for this operation
						if (indexInserted) {
							rewind_block_index_tail();
							idxEntry->value.store(nullptr, std::memory_order_relaxed);
						}
						currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);
						for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) {
							currentTailIndex += static_cast<index_t>(BLOCK_SIZE);
							idxEntry = get_block_index_entry_for_index(currentTailIndex);
							idxEntry->value.store(nullptr, std::memory_order_relaxed);
							rewind_block_index_tail();
						}
						this->parent->add_blocks_to_free_list(firstAllocatedBlock);
						this->tailBlock = startBlock;
						
						return false;
					}
					
#ifdef MCDBGQ_TRACKMEM
					newBlock->owner = this;
#endif
					newBlock->ConcurrentQueue::Block::template reset_empty<implicit_context>();
					newBlock->next = nullptr;
					
					// Insert the new block into the index
					idxEntry->value.store(newBlock, std::memory_order_relaxed);
					
					// Store the chain of blocks so that we can undo if later allocations fail,
					// and so that we can find the blocks when we do the actual enqueueing
					if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr) {
						assert(this->tailBlock != nullptr);
						this->tailBlock->next = newBlock;
					}
					this->tailBlock = newBlock;
					endBlock = newBlock;
					firstAllocatedBlock = firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock;
				} while (blockBaseDiff > 0);
			}
			
			// Enqueue, one block at a time
			index_t newTailIndex = startTailIndex + static_cast<index_t>(count);
			currentTailIndex = startTailIndex;
			this->tailBlock = startBlock;
			assert((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0);
			if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) {
				this->tailBlock = firstAllocatedBlock;
			}
			while (true) {
				auto stopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
				if (details::circular_less_than<index_t>(newTailIndex, stopIndex)) {
					stopIndex = newTailIndex;
				}
				if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) {
					while (currentTailIndex != stopIndex) {
						new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++);
					}
				}
				else {
					MOODYCAMEL_TRY {
						while (currentTailIndex != stopIndex) {
							new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));
							++currentTailIndex;
							++itemFirst;
						}
					}
					MOODYCAMEL_CATCH (...) {
						auto constructedStopIndex = currentTailIndex;
						auto lastBlockEnqueued = this->tailBlock;
						
						if (!details::is_trivially_destructible<T>::value) {
							auto block = startBlock;
							if ((startTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0) {
								block = firstAllocatedBlock;
							}
							currentTailIndex = startTailIndex;
							while (true) {
								stopIndex = (currentTailIndex & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
								if (details::circular_less_than<index_t>(constructedStopIndex, stopIndex)) {
									stopIndex = constructedStopIndex;
								}
								while (currentTailIndex != stopIndex) {
									(*block)[currentTailIndex++]->~T();
								}
								if (block == lastBlockEnqueued) {
									break;
								}
								block = block->next;
							}
						}
						
						currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);
						for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) {
							currentTailIndex += static_cast<index_t>(BLOCK_SIZE);
							auto idxEntry = get_block_index_entry_for_index(currentTailIndex);
							idxEntry->value.store(nullptr, std::memory_order_relaxed);
							rewind_block_index_tail();
						}
						this->parent->add_blocks_to_free_list(firstAllocatedBlock);
						this->tailBlock = startBlock;
						MOODYCAMEL_RETHROW;
					}
				}
				
				if (this->tailBlock == endBlock) {
					assert(currentTailIndex == newTailIndex);
					break;
				}
				this->tailBlock = this->tailBlock->next;
			}
			this->tailIndex.store(newTailIndex, std::memory_order_release);
			return true;
		}
		
		template<typename It>
		size_t dequeue_bulk(It& itemFirst, size_t max)
		{
			auto tail = this->tailIndex.load(std::memory_order_relaxed);
			auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);
			auto desiredCount = static_cast<size_t>(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit));
			if (details::circular_less_than<size_t>(0, desiredCount)) {
				desiredCount = desiredCount < max ? desiredCount : max;
				std::atomic_thread_fence(std::memory_order_acquire);
				
				auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);
				
				tail = this->tailIndex.load(std::memory_order_acquire);
				auto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit));
				if (details::circular_less_than<size_t>(0, actualCount)) {
					actualCount = desiredCount < actualCount ? desiredCount : actualCount;
					if (actualCount < desiredCount) {
						this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release);
					}
					
					// Get the first index. Note that since there's guaranteed to be at least actualCount elements, this
					// will never exceed tail.
					auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel);
					
					// Iterate the blocks and dequeue
					auto index = firstIndex;
					BlockIndexHeader* localBlockIndex;
					auto indexIndex = get_block_index_index_for_index(index, localBlockIndex);
					do {
						auto blockStartIndex = index;
						auto endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
						endIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;
						
						auto entry = localBlockIndex->index[indexIndex];
						auto block = entry->value.load(std::memory_order_relaxed);
						if (MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) {
							while (index != endIndex) {
								auto& el = *((*block)[index]);
								*itemFirst++ = std::move(el);
								el.~T();
								++index;
							}
						}
						else {
							MOODYCAMEL_TRY {
								while (index != endIndex) {
									auto& el = *((*block)[index]);
									*itemFirst = std::move(el);
									++itemFirst;
									el.~T();
									++index;
								}
							}
							MOODYCAMEL_CATCH (...) {
								do {
									entry = localBlockIndex->index[indexIndex];
									block = entry->value.load(std::memory_order_relaxed);
									while (index != endIndex) {
										(*block)[index++]->~T();
									}
									
									if (block->ConcurrentQueue::Block::template set_many_empty<implicit_context>(blockStartIndex, static_cast<size_t>(endIndex - blockStartIndex))) {
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
										debug::DebugLock lock(mutex);
#endif
										entry->value.store(nullptr, std::memory_order_relaxed);
										this->parent->add_block_to_free_list(block);
									}
									indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1);
									
									blockStartIndex = index;
									endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);
									endIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;
								} while (index != firstIndex + actualCount);
								
								MOODYCAMEL_RETHROW;
							}
						}
						if (block->ConcurrentQueue::Block::template set_many_empty<implicit_context>(blockStartIndex, static_cast<size_t>(endIndex - blockStartIndex))) {
							{
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
								debug::DebugLock lock(mutex);
#endif
								// Note that the set_many_empty above did a release, meaning that anybody who acquires the block
								// we're about to free can use it safely since our writes (and reads!) will have happened-before then.
								entry->value.store(nullptr, std::memory_order_relaxed);
							}
							this->parent->add_block_to_free_list(block);		// releases the above store
						}
						indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1);
					} while (index != firstIndex + actualCount);
					
					return actualCount;
				}
				else {
					this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release);
				}
			}
			
			return 0;
		}
		
	private:
		// The block size must be > 1, so any number with the low bit set is an invalid block base index
		static const index_t INVALID_BLOCK_BASE = 1;
		
		struct BlockIndexEntry
		{
			std::atomic<index_t> key;
			std::atomic<Block*> value;
		};
		
		struct BlockIndexHeader
		{
			size_t capacity;
			std::atomic<size_t> tail;
			BlockIndexEntry* entries;
			BlockIndexEntry** index;
			BlockIndexHeader* prev;
		};
		
		template<AllocationMode allocMode>
		inline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, index_t blockStartIndex)
		{
			auto localBlockIndex = blockIndex.load(std::memory_order_relaxed);		// We're the only writer thread, relaxed is OK
			if (localBlockIndex == nullptr) {
				return false;  // this can happen if new_block_index failed in the constructor
			}
			auto newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1);
			idxEntry = localBlockIndex->index[newTail];
			if (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE ||
				idxEntry->value.load(std::memory_order_relaxed) == nullptr) {
				
				idxEntry->key.store(blockStartIndex, std::memory_order_relaxed);
				localBlockIndex->tail.store(newTail, std::memory_order_release);
				return true;
			}
			
			// No room in the old block index, try to allocate another one!
			MOODYCAMEL_CONSTEXPR_IF (allocMode == CannotAlloc) {
				return false;
			}
			else if (!new_block_index()) {
				return false;
			}
			localBlockIndex = blockIndex.load(std::memory_order_relaxed);
			newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1);
			idxEntry = localBlockIndex->index[newTail];
			assert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE);
			idxEntry->key.store(blockStartIndex, std::memory_order_relaxed);
			localBlockIndex->tail.store(newTail, std::memory_order_release);
			return true;
		}
		
		inline void rewind_block_index_tail()
		{
			auto localBlockIndex = blockIndex.load(std::memory_order_relaxed);
			localBlockIndex->tail.store((localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & (localBlockIndex->capacity - 1), std::memory_order_relaxed);
		}
		
		inline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const
		{
			BlockIndexHeader* localBlockIndex;
			auto idx = get_block_index_index_for_index(index, localBlockIndex);
			return localBlockIndex->index[idx];
		}
		
		inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const
		{
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
			debug::DebugLock lock(mutex);
#endif
			index &= ~static_cast<index_t>(BLOCK_SIZE - 1);
			localBlockIndex = blockIndex.load(std::memory_order_acquire);
			auto tail = localBlockIndex->tail.load(std::memory_order_acquire);
			auto tailBase = localBlockIndex->index[tail]->key.load(std::memory_order_relaxed);
			assert(tailBase != INVALID_BLOCK_BASE);
			// Note: Must use division instead of shift because the index may wrap around, causing a negative
			// offset, whose negativity we want to preserve
			auto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(index - tailBase) / BLOCK_SIZE);
			size_t idx = (tail + offset) & (localBlockIndex->capacity - 1);
			assert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == index && localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != nullptr);
			return idx;
		}
		
		bool new_block_index()
		{
			auto prev = blockIndex.load(std::memory_order_relaxed);
			size_t prevCapacity = prev == nullptr ? 0 : prev->capacity;
			auto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity;
			auto raw = static_cast<char*>((Traits::malloc)(
				sizeof(BlockIndexHeader) +
				std::alignment_of<BlockIndexEntry>::value - 1 + sizeof(BlockIndexEntry) * entryCount +
				std::alignment_of<BlockIndexEntry*>::value - 1 + sizeof(BlockIndexEntry*) * nextBlockIndexCapacity));
			if (raw == nullptr) {
				return false;
			}
			
			auto header = new (raw) BlockIndexHeader;
			auto entries = reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>(raw + sizeof(BlockIndexHeader)));
			auto index = reinterpret_cast<BlockIndexEntry**>(details::align_for<BlockIndexEntry*>(reinterpret_cast<char*>(entries) + sizeof(BlockIndexEntry) * entryCount));
			if (prev != nullptr) {
				auto prevTail = prev->tail.load(std::memory_order_relaxed);
				auto prevPos = prevTail;
				size_t i = 0;
				do {
					prevPos = (prevPos + 1) & (prev->capacity - 1);
					index[i++] = prev->index[prevPos];
				} while (prevPos != prevTail);
				assert(i == prevCapacity);
			}
			for (size_t i = 0; i != entryCount; ++i) {
				new (entries + i) BlockIndexEntry;
				entries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed);
				index[prevCapacity + i] = entries + i;
			}
			header->prev = prev;
			header->entries = entries;
			header->index = index;
			header->capacity = nextBlockIndexCapacity;
			header->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), std::memory_order_relaxed);
			
			blockIndex.store(header, std::memory_order_release);
			
			nextBlockIndexCapacity <<= 1;
			
			return true;
		}
		
	private:
		size_t nextBlockIndexCapacity;
		std::atomic<BlockIndexHeader*> blockIndex;

#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
	public:
		details::ThreadExitListener threadExitListener;
	private:
#endif
		
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
	public:
		ImplicitProducer* nextImplicitProducer;
	private:
#endif

#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
		mutable debug::DebugMutex mutex;
#endif
#ifdef MCDBGQ_TRACKMEM
		friend struct MemStats;
#endif
	};
	
	
	//////////////////////////////////
	// Block pool manipulation
	//////////////////////////////////
	
	void populate_initial_block_list(size_t blockCount)
	{
		initialBlockPoolSize = blockCount;
		if (initialBlockPoolSize == 0) {
			initialBlockPool = nullptr;
			return;
		}
		
		initialBlockPool = create_array<Block>(blockCount);
		if (initialBlockPool == nullptr) {
			initialBlockPoolSize = 0;
		}
		for (size_t i = 0; i < initialBlockPoolSize; ++i) {
			initialBlockPool[i].dynamicallyAllocated = false;
		}
	}
	
	inline Block* try_get_block_from_initial_pool()
	{
		if (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) {
			return nullptr;
		}
		
		auto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed);
		
		return index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr;
	}
	
	inline void add_block_to_free_list(Block* block)
	{
#ifdef MCDBGQ_TRACKMEM
		block->owner = nullptr;
#endif
		freeList.add(block);
	}
	
	inline void add_blocks_to_free_list(Block* block)
	{
		while (block != nullptr) {
			auto next = block->next;
			add_block_to_free_list(block);
			block = next;
		}
	}
	
	inline Block* try_get_block_from_free_list()
	{
		return freeList.try_get();
	}
	
	// Gets a free block from one of the memory pools, or allocates a new one (if applicable)
	template<AllocationMode canAlloc>
	Block* requisition_block()
	{
		auto block = try_get_block_from_initial_pool();
		if (block != nullptr) {
			return block;
		}
		
		block = try_get_block_from_free_list();
		if (block != nullptr) {
			return block;
		}
		
		MOODYCAMEL_CONSTEXPR_IF (canAlloc == CanAlloc) {
			return create<Block>();
		}
		else {
			return nullptr;
		}
	}
	

#ifdef MCDBGQ_TRACKMEM
	public:
		struct MemStats {
			size_t allocatedBlocks;
			size_t usedBlocks;
			size_t freeBlocks;
			size_t ownedBlocksExplicit;
			size_t ownedBlocksImplicit;
			size_t implicitProducers;
			size_t explicitProducers;
			size_t elementsEnqueued;
			size_t blockClassBytes;
			size_t queueClassBytes;
			size_t implicitBlockIndexBytes;
			size_t explicitBlockIndexBytes;
			
			friend class ConcurrentQueue;
			
		private:
			static MemStats getFor(ConcurrentQueue* q)
			{
				MemStats stats = { 0 };
				
				stats.elementsEnqueued = q->size_approx();
			
				auto block = q->freeList.head_unsafe();
				while (block != nullptr) {
					++stats.allocatedBlocks;
					++stats.freeBlocks;
					block = block->freeListNext.load(std::memory_order_relaxed);
				}
				
				for (auto ptr = q->producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {
					bool implicit = dynamic_cast<ImplicitProducer*>(ptr) != nullptr;
					stats.implicitProducers += implicit ? 1 : 0;
					stats.explicitProducers += implicit ? 0 : 1;
					
					if (implicit) {
						auto prod = static_cast<ImplicitProducer*>(ptr);
						stats.queueClassBytes += sizeof(ImplicitProducer);
						auto head = prod->headIndex.load(std::memory_order_relaxed);
						auto tail = prod->tailIndex.load(std::memory_order_relaxed);
						auto hash = prod->blockIndex.load(std::memory_order_relaxed);
						if (hash != nullptr) {
							for (size_t i = 0; i != hash->capacity; ++i) {
								if (hash->index[i]->key.load(std::memory_order_relaxed) != ImplicitProducer::INVALID_BLOCK_BASE && hash->index[i]->value.load(std::memory_order_relaxed) != nullptr) {
									++stats.allocatedBlocks;
									++stats.ownedBlocksImplicit;
								}
							}
							stats.implicitBlockIndexBytes += hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry);
							for (; hash != nullptr; hash = hash->prev) {
								stats.implicitBlockIndexBytes += sizeof(typename ImplicitProducer::BlockIndexHeader) + hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry*);
							}
						}
						for (; details::circular_less_than<index_t>(head, tail); head += BLOCK_SIZE) {
							//auto block = prod->get_block_index_entry_for_index(head);
							++stats.usedBlocks;
						}
					}
					else {
						auto prod = static_cast<ExplicitProducer*>(ptr);
						stats.queueClassBytes += sizeof(ExplicitProducer);
						auto tailBlock = prod->tailBlock;
						bool wasNonEmpty = false;
						if (tailBlock != nullptr) {
							auto block = tailBlock;
							do {
								++stats.allocatedBlocks;
								if (!block->ConcurrentQueue::Block::template is_empty<explicit_context>() || wasNonEmpty) {
									++stats.usedBlocks;
									wasNonEmpty = wasNonEmpty || block != tailBlock;
								}
								++stats.ownedBlocksExplicit;
								block = block->next;
							} while (block != tailBlock);
						}
						auto index = prod->blockIndex.load(std::memory_order_relaxed);
						while (index != nullptr) {
							stats.explicitBlockIndexBytes += sizeof(typename ExplicitProducer::BlockIndexHeader) + index->size * sizeof(typename ExplicitProducer::BlockIndexEntry);
							index = static_cast<typename ExplicitProducer::BlockIndexHeader*>(index->prev);
						}
					}
				}
				
				auto freeOnInitialPool = q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= q->initialBlockPoolSize ? 0 : q->initialBlockPoolSize - q->initialBlockPoolIndex.load(std::memory_order_relaxed);
				stats.allocatedBlocks += freeOnInitialPool;
				stats.freeBlocks += freeOnInitialPool;
				
				stats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks;
				stats.queueClassBytes += sizeof(ConcurrentQueue);
				
				return stats;
			}
		};
		
		// For debugging only. Not thread-safe.
		MemStats getMemStats()
		{
			return MemStats::getFor(this);
		}
	private:
		friend struct MemStats;
#endif
	
	
	//////////////////////////////////
	// Producer list manipulation
	//////////////////////////////////	
	
	ProducerBase* recycle_or_create_producer(bool isExplicit)
	{
		bool recycled;
		return recycle_or_create_producer(isExplicit, recycled);
	}
	
	ProducerBase* recycle_or_create_producer(bool isExplicit, bool& recycled)
	{
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
		debug::DebugLock lock(implicitProdMutex);
#endif
		// Try to re-use one first
		for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {
			if (ptr->inactive.load(std::memory_order_relaxed) && ptr->isExplicit == isExplicit) {
				bool expected = true;
				if (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) {
					// We caught one! It's been marked as activated, the caller can have it
					recycled = true;
					return ptr;
				}
			}
		}
		
		recycled = false;
		return add_producer(isExplicit ? static_cast<ProducerBase*>(create<ExplicitProducer>(this)) : create<ImplicitProducer>(this));
	}
	
	ProducerBase* add_producer(ProducerBase* producer)
	{
		// Handle failed memory allocation
		if (producer == nullptr) {
			return nullptr;
		}
		
		producerCount.fetch_add(1, std::memory_order_relaxed);
		
		// Add it to the lock-free list
		auto prevTail = producerListTail.load(std::memory_order_relaxed);
		do {
			producer->next = prevTail;
		} while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed));
		
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
		if (producer->isExplicit) {
			auto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed);
			do {
				static_cast<ExplicitProducer*>(producer)->nextExplicitProducer = prevTailExplicit;
			} while (!explicitProducers.compare_exchange_weak(prevTailExplicit, static_cast<ExplicitProducer*>(producer), std::memory_order_release, std::memory_order_relaxed));
		}
		else {
			auto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed);
			do {
				static_cast<ImplicitProducer*>(producer)->nextImplicitProducer = prevTailImplicit;
			} while (!implicitProducers.compare_exchange_weak(prevTailImplicit, static_cast<ImplicitProducer*>(producer), std::memory_order_release, std::memory_order_relaxed));
		}
#endif
		
		return producer;
	}
	
	void reown_producers()
	{
		// After another instance is moved-into/swapped-with this one, all the
		// producers we stole still think their parents are the other queue.
		// So fix them up!
		for (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) {
			ptr->parent = this;
		}
	}
	
	
	//////////////////////////////////
	// Implicit producer hash
	//////////////////////////////////
	
	struct ImplicitProducerKVP
	{
		std::atomic<details::thread_id_t> key;
		ImplicitProducer* value;		// No need for atomicity since it's only read by the thread that sets it in the first place
		
		ImplicitProducerKVP() : value(nullptr) { }
		
		ImplicitProducerKVP(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT
		{
			key.store(other.key.load(std::memory_order_relaxed), std::memory_order_relaxed);
			value = other.value;
		}
		
		inline ImplicitProducerKVP& operator=(ImplicitProducerKVP&& other) MOODYCAMEL_NOEXCEPT
		{
			swap(other);
			return *this;
		}
		
		inline void swap(ImplicitProducerKVP& other) MOODYCAMEL_NOEXCEPT
		{
			if (this != &other) {
				details::swap_relaxed(key, other.key);
				std::swap(value, other.value);
			}
		}
	};
	
	template<typename XT, typename XTraits>
	friend void duckdb_moodycamel::swap(typename ConcurrentQueue<XT, XTraits>::ImplicitProducerKVP&, typename ConcurrentQueue<XT, XTraits>::ImplicitProducerKVP&) MOODYCAMEL_NOEXCEPT;
	
	struct ImplicitProducerHash
	{
		size_t capacity;
		ImplicitProducerKVP* entries;
		ImplicitProducerHash* prev;
	};
	
	inline void populate_initial_implicit_producer_hash()
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) {
			return;
		}
		else {
			implicitProducerHashCount.store(0, std::memory_order_relaxed);
			auto hash = &initialImplicitProducerHash;
			hash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE;
			hash->entries = &initialImplicitProducerHashEntries[0];
			for (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) {
				initialImplicitProducerHashEntries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed);
			}
			hash->prev = nullptr;
			implicitProducerHash.store(hash, std::memory_order_relaxed);
		}
	}
	
	void swap_implicit_producer_hashes(ConcurrentQueue& other)
	{
		MOODYCAMEL_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) {
			return;
		}
		else {
			// Swap (assumes our implicit producer hash is initialized)
			initialImplicitProducerHashEntries.swap(other.initialImplicitProducerHashEntries);
			initialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0];
			other.initialImplicitProducerHash.entries = &other.initialImplicitProducerHashEntries[0];
			
			details::swap_relaxed(implicitProducerHashCount, other.implicitProducerHashCount);
			
			details::swap_relaxed(implicitProducerHash, other.implicitProducerHash);
			if (implicitProducerHash.load(std::memory_order_relaxed) == &other.initialImplicitProducerHash) {
				implicitProducerHash.store(&initialImplicitProducerHash, std::memory_order_relaxed);
			}
			else {
				ImplicitProducerHash* hash;
				for (hash = implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &other.initialImplicitProducerHash; hash = hash->prev) {
					continue;
				}
				hash->prev = &initialImplicitProducerHash;
			}
			if (other.implicitProducerHash.load(std::memory_order_relaxed) == &initialImplicitProducerHash) {
				other.implicitProducerHash.store(&other.initialImplicitProducerHash, std::memory_order_relaxed);
			}
			else {
				ImplicitProducerHash* hash;
				for (hash = other.implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &initialImplicitProducerHash; hash = hash->prev) {
					continue;
				}
				hash->prev = &other.initialImplicitProducerHash;
			}
		}
	}
	
	// Only fails (returns nullptr) if memory allocation fails
	ImplicitProducer* get_or_add_implicit_producer()
	{
		// Note that since the data is essentially thread-local (key is thread ID),
		// there's a reduced need for fences (memory ordering is already consistent
		// for any individual thread), except for the current table itself.
		
		// Start by looking for the thread ID in the current and all previous hash tables.
		// If it's not found, it must not be in there yet, since this same thread would
		// have added it previously to one of the tables that we traversed.
		
		// Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table
		
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
		debug::DebugLock lock(implicitProdMutex);
#endif
		
		auto id = details::thread_id();
		auto hashedId = details::hash_thread_id(id);
		
		auto mainHash = implicitProducerHash.load(std::memory_order_acquire);
		assert(mainHash != nullptr);  // silence clang-tidy and MSVC warnings (hash cannot be null)
		for (auto hash = mainHash; hash != nullptr; hash = hash->prev) {
			// Look for the id in this hash
			auto index = hashedId;
			while (true) {		// Not an infinite loop because at least one slot is free in the hash table
				index &= hash->capacity - 1;
				
				auto probedKey = hash->entries[index].key.load(std::memory_order_relaxed);
				if (probedKey == id) {
					// Found it! If we had to search several hashes deep, though, we should lazily add it
					// to the current main hash table to avoid the extended search next time.
					// Note there's guaranteed to be room in the current hash table since every subsequent
					// table implicitly reserves space for all previous tables (there's only one
					// implicitProducerHashCount).
					auto value = hash->entries[index].value;
					if (hash != mainHash) {
						index = hashedId;
						while (true) {
							index &= mainHash->capacity - 1;
							probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed);
							auto empty = details::invalid_thread_id;
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
							auto reusable = details::invalid_thread_id2;
							if ((probedKey == empty    && mainHash->entries[index].key.compare_exchange_strong(empty,    id, std::memory_order_relaxed, std::memory_order_relaxed)) ||
								(probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) {
#else
							if ((probedKey == empty    && mainHash->entries[index].key.compare_exchange_strong(empty,    id, std::memory_order_relaxed, std::memory_order_relaxed))) {
#endif
								mainHash->entries[index].value = value;
								break;
							}
							++index;
						}
					}
					
					return value;
				}
				if (probedKey == details::invalid_thread_id) {
					break;		// Not in this hash table
				}
				++index;
			}
		}
		
		// Insert!
		auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed);
		while (true) {
			// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
			if (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) {
				// We've acquired the resize lock, try to allocate a bigger hash table.
				// Note the acquire fence synchronizes with the release fence at the end of this block, and hence when
				// we reload implicitProducerHash it must be the most recent version (it only gets changed within this
				// locked block).
				mainHash = implicitProducerHash.load(std::memory_order_acquire);
				if (newCount >= (mainHash->capacity >> 1)) {
					auto newCapacity = mainHash->capacity << 1;
					while (newCount >= (newCapacity >> 1)) {
						newCapacity <<= 1;
					}
					auto raw = static_cast<char*>((Traits::malloc)(sizeof(ImplicitProducerHash) + std::alignment_of<ImplicitProducerKVP>::value - 1 + sizeof(ImplicitProducerKVP) * newCapacity));
					if (raw == nullptr) {
						// Allocation failed
						implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed);
						implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);
						return nullptr;
					}
					
					auto newHash = new (raw) ImplicitProducerHash;
					newHash->capacity = newCapacity;
					newHash->entries = reinterpret_cast<ImplicitProducerKVP*>(details::align_for<ImplicitProducerKVP>(raw + sizeof(ImplicitProducerHash)));
					for (size_t i = 0; i != newCapacity; ++i) {
						new (newHash->entries + i) ImplicitProducerKVP;
						newHash->entries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed);
					}
					newHash->prev = mainHash;
					implicitProducerHash.store(newHash, std::memory_order_release);
					implicitProducerHashResizeInProgress.clear(std::memory_order_release);
					mainHash = newHash;
				}
				else {
					implicitProducerHashResizeInProgress.clear(std::memory_order_release);
				}
			}
			
			// If it's < three-quarters full, add to the old one anyway so that we don't have to wait for the next table
			// to finish being allocated by another thread (and if we just finished allocating above, the condition will
			// always be true)
			if (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) {
				bool recycled;
				auto producer = static_cast<ImplicitProducer*>(recycle_or_create_producer(false, recycled));
				if (producer == nullptr) {
					implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed);
					return nullptr;
				}
				if (recycled) {
					implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed);
				}
				
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
				producer->threadExitListener.callback = &ConcurrentQueue::implicit_producer_thread_exited_callback;
				producer->threadExitListener.userData = producer;
				details::ThreadExitNotifier::subscribe(&producer->threadExitListener);
#endif
				
				auto index = hashedId;
				while (true) {
					index &= mainHash->capacity - 1;
					auto probedKey = mainHash->entries[index].key.load(std::memory_order_relaxed);
					
					auto empty = details::invalid_thread_id;
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
					auto reusable = details::invalid_thread_id2;
					if ((probedKey == empty    && mainHash->entries[index].key.compare_exchange_strong(empty,    id, std::memory_order_relaxed, std::memory_order_relaxed)) ||
						(probedKey == reusable && mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_acquire, std::memory_order_acquire))) {
#else
					if ((probedKey == empty    && mainHash->entries[index].key.compare_exchange_strong(empty,    id, std::memory_order_relaxed, std::memory_order_relaxed))) {
#endif
						mainHash->entries[index].value = producer;
						break;
					}
					++index;
				}
				return producer;
			}
			
			// Hmm, the old hash is quite full and somebody else is busy allocating a new one.
			// We need to wait for the allocating thread to finish (if it succeeds, we add, if not,
			// we try to allocate ourselves).
			mainHash = implicitProducerHash.load(std::memory_order_acquire);
		}
	}
	
#ifdef MOODYCAMEL_CPP11_THREAD_LOCAL_SUPPORTED
	void implicit_producer_thread_exited(ImplicitProducer* producer)
	{
		// Remove from thread exit listeners
		details::ThreadExitNotifier::unsubscribe(&producer->threadExitListener);
		
		// Remove from hash
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
		debug::DebugLock lock(implicitProdMutex);
#endif
		auto hash = implicitProducerHash.load(std::memory_order_acquire);
		assert(hash != nullptr);		// The thread exit listener is only registered if we were added to a hash in the first place
		auto id = details::thread_id();
		auto hashedId = details::hash_thread_id(id);
		details::thread_id_t probedKey;
		
		// We need to traverse all the hashes just in case other threads aren't on the current one yet and are
		// trying to add an entry thinking there's a free slot (because they reused a producer)
		for (; hash != nullptr; hash = hash->prev) {
			auto index = hashedId;
			do {
				index &= hash->capacity - 1;
				probedKey = hash->entries[index].key.load(std::memory_order_relaxed);
				if (probedKey == id) {
					hash->entries[index].key.store(details::invalid_thread_id2, std::memory_order_release);
					break;
				}
				++index;
			} while (probedKey != details::invalid_thread_id);		// Can happen if the hash has changed but we weren't put back in it yet, or if we weren't added to this hash in the first place
		}
		
		// Mark the queue as being recyclable
		producer->inactive.store(true, std::memory_order_release);
	}
	
	static void implicit_producer_thread_exited_callback(void* userData)
	{
		auto producer = static_cast<ImplicitProducer*>(userData);
		auto queue = producer->parent;
		queue->implicit_producer_thread_exited(producer);
	}
#endif
	
	//////////////////////////////////
	// Utility functions
	//////////////////////////////////

	template<typename TAlign>
	static inline void* aligned_malloc(size_t size)
	{
		if (std::alignment_of<TAlign>::value <= std::alignment_of<details::max_align_t>::value)
			return (Traits::malloc)(size);
		size_t alignment = std::alignment_of<TAlign>::value;
		void* raw = (Traits::malloc)(size + alignment - 1 + sizeof(void*));
		if (!raw)
			return nullptr;
		char* ptr = details::align_for<TAlign>(reinterpret_cast<char*>(raw) + sizeof(void*));
		*(reinterpret_cast<void**>(ptr) - 1) = raw;
		return ptr;
	}

	template<typename TAlign>
	static inline void aligned_free(void* ptr)
	{
		if (std::alignment_of<TAlign>::value <= std::alignment_of<details::max_align_t>::value)
			return (Traits::free)(ptr);
		(Traits::free)(ptr ? *(reinterpret_cast<void**>(ptr) - 1) : nullptr);
	}

	template<typename U>
	static inline U* create_array(size_t count)
	{
		assert(count > 0);
		U* p = static_cast<U*>(aligned_malloc<U>(sizeof(U) * count));
		if (p == nullptr)
			return nullptr;

		for (size_t i = 0; i != count; ++i)
			new (p + i) U();
		return p;
	}

	template<typename U>
	static inline void destroy_array(U* p, size_t count)
	{
		if (p != nullptr) {
			assert(count > 0);
			for (size_t i = count; i != 0; )
				(p + --i)->~U();
		}
		aligned_free<U>(p);
	}

	template<typename U>
	static inline U* create()
	{
		void* p = aligned_malloc<U>(sizeof(U));
		return p != nullptr ? new (p) U : nullptr;
	}

	template<typename U, typename A1>
	static inline U* create(A1&& a1)
	{
		void* p = aligned_malloc<U>(sizeof(U));
		return p != nullptr ? new (p) U(std::forward<A1>(a1)) : nullptr;
	}

	template<typename U>
	static inline void destroy(U* p)
	{
		if (p != nullptr)
			p->~U();
		aligned_free<U>(p);
	}

private:
	std::atomic<ProducerBase*> producerListTail;
	std::atomic<std::uint32_t> producerCount;
	
	std::atomic<size_t> initialBlockPoolIndex;
	Block* initialBlockPool;
	size_t initialBlockPoolSize;
	
#ifndef MCDBGQ_USEDEBUGFREELIST
	FreeList<Block> freeList;
#else
	debug::DebugFreeList<Block> freeList;
#endif
	
	std::atomic<ImplicitProducerHash*> implicitProducerHash;
	std::atomic<size_t> implicitProducerHashCount;		// Number of slots logically used
	ImplicitProducerHash initialImplicitProducerHash;
	std::array<ImplicitProducerKVP, INITIAL_IMPLICIT_PRODUCER_HASH_SIZE> initialImplicitProducerHashEntries;
	std::atomic_flag implicitProducerHashResizeInProgress;
	
	std::atomic<std::uint32_t> nextExplicitConsumerId;
	std::atomic<std::uint32_t> globalExplicitConsumerOffset;
	
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
	debug::DebugMutex implicitProdMutex;
#endif
	
#ifdef MOODYCAMEL_QUEUE_INTERNAL_DEBUG
	std::atomic<ExplicitProducer*> explicitProducers;
	std::atomic<ImplicitProducer*> implicitProducers;
#endif
};


template<typename T, typename Traits>
ProducerToken::ProducerToken(ConcurrentQueue<T, Traits>& queue)
	: producer(queue.recycle_or_create_producer(true))
{
	if (producer != nullptr) {
		producer->token = this;
	}
}

template<typename T, typename Traits>
ProducerToken::ProducerToken(BlockingConcurrentQueue<T, Traits>& queue)
	: producer(reinterpret_cast<ConcurrentQueue<T, Traits>*>(&queue)->recycle_or_create_producer(true))
{
	if (producer != nullptr) {
		producer->token = this;
	}
}

template<typename T, typename Traits>
ConsumerToken::ConsumerToken(ConcurrentQueue<T, Traits>& queue)
	: itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr)
{
	initialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release);
	lastKnownGlobalOffset = -1;
}

template<typename T, typename Traits>
ConsumerToken::ConsumerToken(BlockingConcurrentQueue<T, Traits>& queue)
	: itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr)
{
	initialOffset = reinterpret_cast<ConcurrentQueue<T, Traits>*>(&queue)->nextExplicitConsumerId.fetch_add(1, std::memory_order_release);
	lastKnownGlobalOffset = -1;
}

template<typename T, typename Traits>
inline void swap(ConcurrentQueue<T, Traits>& a, ConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT
{
	a.swap(b);
}

inline void swap(ProducerToken& a, ProducerToken& b) MOODYCAMEL_NOEXCEPT
{
	a.swap(b);
}

inline void swap(ConsumerToken& a, ConsumerToken& b) MOODYCAMEL_NOEXCEPT
{
	a.swap(b);
}

template<typename T, typename Traits>
inline void swap(typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& a, typename ConcurrentQueue<T, Traits>::ImplicitProducerKVP& b) MOODYCAMEL_NOEXCEPT
{
	a.swap(b);
}

}



// LICENSE_CHANGE_END


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #10
// See the end of this file for a list

// Provides an efficient implementation of a semaphore (LightweightSemaphore).
// This is an extension of Jeff Preshing's sempahore implementation (licensed
// under the terms of its separate zlib license) that has been adapted and
// extended by Cameron Desrochers.



#include <cstddef> // For std::size_t
#include <atomic>
#include <type_traits> // For std::make_signed<T>

#if defined(_WIN32)
// Avoid including windows.h in a header; we only need a handful of
// items, so we'll redeclare them here (this is relatively safe since
// the API generally has to remain stable between Windows versions).
// I know this is an ugly hack but it still beats polluting the global
// namespace with thousands of generic names or adding a .cpp for nothing.
extern "C" {
	struct _SECURITY_ATTRIBUTES;
	__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName);
	__declspec(dllimport) int __stdcall CloseHandle(void* hObject);
	__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds);
	__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount);
}
#elif defined(__MACH__)
#include <mach/mach.h>
#elif defined(__unix__)
#include <semaphore.h>
#include <chrono>
#endif

namespace duckdb_moodycamel
{
namespace details
{

// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's
// portable + lightweight semaphore implementations, originally from
// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h
// LICENSE:
// Copyright (c) 2015 Jeff Preshing
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//	claim that you wrote the original software. If you use this software
//	in a product, an acknowledgement in the product documentation would be
//	appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
//	misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#if defined(_WIN32)
class Semaphore
{
private:
	void* m_hSema;

	Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
	Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;

public:
	Semaphore(int initialCount = 0)
	{
		assert(initialCount >= 0);
		const long maxLong = 0x7fffffff;
		m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr);
		assert(m_hSema);
	}

	~Semaphore()
	{
		CloseHandle(m_hSema);
	}

	bool wait()
	{
		const unsigned long infinite = 0xffffffff;
		return WaitForSingleObject(m_hSema, infinite) == 0;
	}

	bool try_wait()
	{
		return WaitForSingleObject(m_hSema, 0) == 0;
	}

	bool timed_wait(std::uint64_t usecs)
	{
		return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0;
	}

	void signal(int count = 1)
	{
		while (!ReleaseSemaphore(m_hSema, count, nullptr));
	}
};
#elif defined(__MACH__)
//---------------------------------------------------------
// Semaphore (Apple iOS and OSX)
// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html
//---------------------------------------------------------
class Semaphore
{
private:
	semaphore_t m_sema;

	Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
	Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;

public:
	Semaphore(int initialCount = 0)
	{
		assert(initialCount >= 0);
		kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
		assert(rc == KERN_SUCCESS);
		(void)rc;
	}

	~Semaphore()
	{
		semaphore_destroy(mach_task_self(), m_sema);
	}

	bool wait()
	{
		return semaphore_wait(m_sema) == KERN_SUCCESS;
	}

	bool try_wait()
	{
		return timed_wait(0);
	}

	bool timed_wait(std::uint64_t timeout_usecs)
	{
		mach_timespec_t ts;
		ts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000);
		ts.tv_nsec = (timeout_usecs % 1000000) * 1000;

		// added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html
		kern_return_t rc = semaphore_timedwait(m_sema, ts);
		return rc == KERN_SUCCESS;
	}

	void signal()
	{
		while (semaphore_signal(m_sema) != KERN_SUCCESS);
	}

	void signal(int count)
	{
		while (count-- > 0)
		{
			while (semaphore_signal(m_sema) != KERN_SUCCESS);
		}
	}
};
#elif defined(__unix__)
//---------------------------------------------------------
// Semaphore (POSIX, Linux)
//---------------------------------------------------------
class Semaphore
{
private:
	sem_t m_sema;

	Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
	Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;

public:
	Semaphore(int initialCount = 0)
	{
		assert(initialCount >= 0);
		int rc = sem_init(&m_sema, 0, initialCount);
		assert(rc == 0);
		(void)rc;
	}

	~Semaphore()
	{
		sem_destroy(&m_sema);
	}

	bool wait()
	{
		// http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error
		int rc;
		do {
			rc = sem_wait(&m_sema);
		} while (rc == -1 && errno == EINTR);
		return rc == 0;
	}

	bool try_wait()
	{
		int rc;
		do {
			rc = sem_trywait(&m_sema);
		} while (rc == -1 && errno == EINTR);
		return rc == 0;
	}

	bool timed_wait(std::uint64_t usecs)
	{
		struct timespec ts;
		const int usecs_in_1_sec = 1000000;
		const int nsecs_in_1_sec = 1000000000;

		// sem_timedwait needs an absolute time
		// hence we need to first obtain the current time
		// and then add the maximum time we want to wait
		// we want to avoid clock_gettime because of linking issues
		// chrono -> timespec conversion from here: https://embeddedartistry.com/blog/2019/01/31/converting-between-timespec-stdchrono/
		auto current_time = std::chrono::system_clock::now();
		auto secs =  std::chrono::time_point_cast<std::chrono::seconds>(current_time);
		auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(current_time) - std::chrono::time_point_cast<std::chrono::nanoseconds>(secs);

		ts.tv_sec = secs.time_since_epoch().count();
		ts.tv_nsec = ns.count();

		// now add the time we want to wait
		ts.tv_sec += usecs / usecs_in_1_sec;
		ts.tv_nsec += (usecs % usecs_in_1_sec) * 1000;

		// sem_timedwait bombs if you have more than 1e9 in tv_nsec
		// so we have to clean things up before passing it in
		if (ts.tv_nsec >= nsecs_in_1_sec) {
			ts.tv_nsec -= nsecs_in_1_sec;
			++ts.tv_sec;
		}

		int rc;
		do {
			rc = sem_timedwait(&m_sema, &ts);
		} while (rc == -1 && errno == EINTR);
		return rc == 0;
	}

	void signal()
	{
		while (sem_post(&m_sema) == -1);
	}

	void signal(int count)
	{
		while (count-- > 0)
		{
			while (sem_post(&m_sema) == -1);
		}
	}
};
#else
#error Unsupported platform! (No semaphore wrapper available)
#endif

}	// end namespace details


//---------------------------------------------------------
// LightweightSemaphore
//---------------------------------------------------------
class LightweightSemaphore
{
public:
	typedef std::make_signed<std::size_t>::type ssize_t;

private:
	std::atomic<ssize_t> m_count;
	details::Semaphore m_sema;

	bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1)
	{
		ssize_t oldCount;
		// Is there a better way to set the initial spin count?
		// If we lower it to 1000, testBenaphore becomes 15x slower on my Core i7-5930K Windows PC,
		// as threads start hitting the kernel semaphore.
		int spin = 10000;
		while (--spin >= 0)
		{
			oldCount = m_count.load(std::memory_order_relaxed);
			if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
				return true;
			std::atomic_signal_fence(std::memory_order_acquire);	 // Prevent the compiler from collapsing the loop.
		}
		oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
		if (oldCount > 0)
			return true;
		if (timeout_usecs < 0)
			return m_sema.wait();
		if (m_sema.timed_wait((std::uint64_t)timeout_usecs))
			return true;
		// At this point, we've timed out waiting for the semaphore, but the
		// count is still decremented indicating we may still be waiting on
		// it. So we have to re-adjust the count, but only if the semaphore
		// wasn't signaled enough times for us too since then. If it was, we
		// need to release the semaphore too.
		while (true)
		{
			oldCount = m_count.load(std::memory_order_acquire);
			if (oldCount >= 0 && m_sema.try_wait())
				return true;
			if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
				return false;
		}
	}

	ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1)
	{
		assert(max > 0);
		ssize_t oldCount;
		int spin = 10000;
		while (--spin >= 0)
		{
			oldCount = m_count.load(std::memory_order_relaxed);
			if (oldCount > 0)
			{
				ssize_t newCount = oldCount > max ? oldCount - max : 0;
				if (m_count.compare_exchange_strong(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))
					return oldCount - newCount;
			}
			std::atomic_signal_fence(std::memory_order_acquire);
		}
		oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
		if (oldCount <= 0)
		{
			if (timeout_usecs < 0)
			{
				if (!m_sema.wait())
					return 0;
			}
			else if (!m_sema.timed_wait((std::uint64_t)timeout_usecs))
			{
				while (true)
				{
					oldCount = m_count.load(std::memory_order_acquire);
					if (oldCount >= 0 && m_sema.try_wait())
						break;
					if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
						return 0;
				}
			}
		}
		if (max > 1)
			return 1 + tryWaitMany(max - 1);
		return 1;
	}

public:
	LightweightSemaphore(ssize_t initialCount = 0) : m_count(initialCount)
	{
		assert(initialCount >= 0);
	}

	bool tryWait()
	{
		ssize_t oldCount = m_count.load(std::memory_order_relaxed);
		while (oldCount > 0)
		{
			if (m_count.compare_exchange_weak(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
				return true;
		}
		return false;
	}

	bool wait()
	{
		return tryWait() || waitWithPartialSpinning();
	}

	bool wait(std::int64_t timeout_usecs)
	{
		return tryWait() || waitWithPartialSpinning(timeout_usecs);
	}

	// Acquires between 0 and (greedily) max, inclusive
	ssize_t tryWaitMany(ssize_t max)
	{
		assert(max >= 0);
		ssize_t oldCount = m_count.load(std::memory_order_relaxed);
		while (oldCount > 0)
		{
			ssize_t newCount = oldCount > max ? oldCount - max : 0;
			if (m_count.compare_exchange_weak(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))
				return oldCount - newCount;
		}
		return 0;
	}

	// Acquires at least one, and (greedily) at most max
	ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs)
	{
		assert(max >= 0);
		ssize_t result = tryWaitMany(max);
		if (result == 0 && max > 0)
			result = waitManyWithPartialSpinning(max, timeout_usecs);
		return result;
	}

	ssize_t waitMany(ssize_t max)
	{
		ssize_t result = waitMany(max, -1);
		assert(result > 0);
		return result;
	}

	void signal(ssize_t count = 1)
	{
		assert(count >= 0);
		ssize_t oldCount = m_count.fetch_add(count, std::memory_order_release);
		ssize_t toRelease = -oldCount < count ? -oldCount : count;
		if (toRelease > 0)
		{
			m_sema.signal((int)toRelease);
		}
	}

	ssize_t availableApprox() const
	{
		ssize_t count = m_count.load(std::memory_order_relaxed);
		return count > 0 ? count : 0;
	}
};

}   // end namespace duckdb_moodycamel


// LICENSE_CHANGE_END
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/query_node/recursive_cte_node.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class RecursiveCTENode : public QueryNode {
public:
	RecursiveCTENode() : QueryNode(QueryNodeType::RECURSIVE_CTE_NODE) {
	}

	string ctename;
	bool union_all;
	//! The left side of the set operation
	unique_ptr<QueryNode> left;
	//! The right side of the set operation
	unique_ptr<QueryNode> right;
	//! Aliases of the recursive CTE node
	vector<string> aliases;

	const vector<unique_ptr<ParsedExpression>> &GetSelectList() const override {
		return left->GetSelectList();
	}

public:
	//! Convert the query node to a string
	string ToString() const override;

	bool Equals(const QueryNode *other) const override;
	//! Create a copy of this SelectNode
	unique_ptr<QueryNode> Copy() const override;

	//! Serializes a QueryNode to a stand-alone binary blob
	void Serialize(FieldWriter &writer) const override;
	//! Deserializes a blob back into a QueryNode
	static unique_ptr<QueryNode> Deserialize(FieldReader &reader);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/transformer.hpp
//
//
//===----------------------------------------------------------------------===//















// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

// this is a bit of a mess from c.h, port.h and some others. Upside is it makes the parser compile with minimal
// dependencies.



#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string>

#ifdef ERROR
#undef ERROR
#endif

typedef uintptr_t PGDatum;
typedef uint64_t PGSize;

typedef uint32_t PGIndex;
typedef uint32_t PGOid;

#define InvalidOid ((PGOid)0)

#ifndef _MSC_VER
#include <assert.h>
#define Assert(a) assert(a);
#define AssertMacro(p) ((void)assert(p))
#else
#define Assert(a) (a);
#define AssertMacro(p) ((void)(p))
#endif
#define _(a) (a)

#define lengthof(array) (sizeof(array) / sizeof((array)[0]))
#define CppConcat(x, y) x##y

#define HIGHBIT (0x80)
#define IS_HIGHBIT_SET(ch) ((unsigned char)(ch)&HIGHBIT)

#define FUNC_MAX_ARGS 100
#define FLEXIBLE_ARRAY_MEMBER

#define DEFAULT_INDEX_TYPE "art"
#define INTERVAL_MASK(b) (1 << (b))

#ifdef _MSC_VER
#define __thread __declspec(thread)
#endif


//typedef struct {
//	int32_t vl_len_;    /* these fields must match ArrayType! */
//	int ndim;         /* always 1 for PGint2vector */
//	int32_t dataoffset; /* always 0 for PGint2vector */
//	PGOid elemtype;
//	int dim1;
//	int lbound1;
//	int16_t values[];
//} PGint2vector;

struct pg_varlena {
	char vl_len_[4];                    /* Do not touch this field directly! */
	char vl_dat[1]; /* Data content is here */
};

typedef struct pg_varlena bytea;

typedef int PGMemoryContext;

namespace duckdb_libpgquery {

typedef enum PGPostgresParserErrors {
	PG_ERRCODE_SYNTAX_ERROR,
	PG_ERRCODE_FEATURE_NOT_SUPPORTED,
	PG_ERRCODE_INVALID_PARAMETER_VALUE,
	PG_ERRCODE_WINDOWING_ERROR,
	PG_ERRCODE_RESERVED_NAME,
	PG_ERRCODE_INVALID_ESCAPE_SEQUENCE,
	PG_ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER,
	ERRCODE_NAME_TOO_LONG
} PGPostgresParserErrors;

typedef enum PGPostgresRelPersistence {
	PG_RELPERSISTENCE_TEMP,
	PG_RELPERSISTENCE_UNLOGGED,
	RELPERSISTENCE_PERMANENT
} PGPostgresRelPersistence;

typedef enum PGPostgresErrorLevel {
	PGUNDEFINED,
	PGNOTICE,
	PGWARNING,
	ERROR
} PGPostgresErrorLevel;

typedef enum PGPostgresAttributIdentityTypes {
	PG_ATTRIBUTE_IDENTITY_ALWAYS,
	ATTRIBUTE_IDENTITY_BY_DEFAULT
} PGPostgresAttributIdentityTypes;

}


// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * parsenodes.h
 *	  definitions for parse tree nodes
 *
 * Many of the node types used in parsetrees include a "location" field.
 * This is a byte (not character) offset in the original source text, to be
 * used for positioning an error cursor when there is an error related to
 * the node.  Access to the original source text is needed to make use of
 * the location.  At the topmost (statement) level, we also provide a
 * statement length, likewise measured in bytes, for convenience in
 * identifying statement boundaries in multi-statement source strings.
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development PGGroup
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/parsenodes.h
 *
 *-------------------------------------------------------------------------
 */




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * bitmapset.h
 *	  PostgreSQL generic bitmap set package
 *
 * A bitmap set can represent any set of nonnegative integers, although
 * it is mainly intended for sets where the maximum value is not large,
 * say at most a few hundred.  By convention, a NULL pointer is always
 * accepted by all operations to represent the empty set.  (But beware
 * that this is not the only representation of the empty set.  Use
 * bms_is_empty() in preference to testing for NULL.)
 *
 *
 * Copyright (c) 2003-2017, PostgreSQL Global Development PGGroup
 *
 * src/include/nodes/bitmapset.h
 *
 *-------------------------------------------------------------------------
 */


#include <cstdint>

namespace duckdb_libpgquery {

/*
 * Forward decl to save including pg_list.h
 */
struct PGList;

/*
 * Data representation
 */

/* The unit size can be adjusted by changing these three declarations: */
#define BITS_PER_BITMAPWORD 32
typedef uint32_t bitmapword;      /* must be an unsigned type */
typedef int32_t signedbitmapword; /* must be the matching signed type */

typedef struct PGBitmapset {
	int nwords;          /* number of words in array */
	bitmapword words[1]; /* really [nwords] */
} PGBitmapset;

/* result of bms_subset_compare */
typedef enum PG_BMS_Comparison {
	PG_BMS_EQUAL,   /* sets are equal */
	PG_BMS_SUBSET1, /* first set is a subset of the second */
	PG_BMS_SUBSET2, /* second set is a subset of the first */
	BMS_DIFFERENT   /* neither set is a subset of the other */
} PG_BMS_Comparison;

/* result of bms_membership */
typedef enum PG_BMS_Membership {
	PG_BMS_EMPTY_SET, /* 0 members */
	PG_BMS_SINGLETON, /* 1 member */
	BMS_MULTIPLE      /* >1 member */
} PG_BMS_Membership;

/*
 * function prototypes in nodes/bitmapset.c
 */

PGBitmapset *bms_copy(const PGBitmapset *a);
bool bms_equal(const PGBitmapset *a, const PGBitmapset *b);
PGBitmapset *bms_make_singleton(int x);
void bms_free(PGBitmapset *a);

PGBitmapset *bms_union(const PGBitmapset *a, const PGBitmapset *b);
PGBitmapset *bms_intersect(const PGBitmapset *a, const PGBitmapset *b);
PGBitmapset *bms_difference(const PGBitmapset *a, const PGBitmapset *b);
bool bms_is_subset(const PGBitmapset *a, const PGBitmapset *b);
PG_BMS_Comparison bms_subset_compare(const PGBitmapset *a, const PGBitmapset *b);
bool bms_is_member(int x, const PGBitmapset *a);
bool bms_overlap(const PGBitmapset *a, const PGBitmapset *b);
bool bms_overlap_list(const PGBitmapset *a, const struct PGList *b);
bool bms_nonempty_difference(const PGBitmapset *a, const PGBitmapset *b);
int bms_singleton_member(const PGBitmapset *a);
bool bms_get_singleton_member(const PGBitmapset *a, int *member);
int bms_num_members(const PGBitmapset *a);

/* optimized tests when we don't need to know exact membership count: */
PG_BMS_Membership bms_membership(const PGBitmapset *a);
bool bms_is_empty(const PGBitmapset *a);

/* these routines recycle (modify or free) their non-const inputs: */

PGBitmapset *bms_add_member(PGBitmapset *a, int x);
PGBitmapset *bms_del_member(PGBitmapset *a, int x);
PGBitmapset *bms_add_members(PGBitmapset *a, const PGBitmapset *b);
PGBitmapset *bms_int_members(PGBitmapset *a, const PGBitmapset *b);
PGBitmapset *bms_del_members(PGBitmapset *a, const PGBitmapset *b);
PGBitmapset *bms_join(PGBitmapset *a, PGBitmapset *b);

/* support for iterating through the integer elements of a set: */
int bms_first_member(PGBitmapset *a);
int bms_next_member(const PGBitmapset *a, int prevbit);

/* support for hashtables using Bitmapsets as keys: */
uint32_t bms_hash_value(const PGBitmapset *a);

}

// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * lockoptions.h
 *	  Common header for some locking-related declarations.
 *
 *
 * Copyright (c) 2014-2017, PostgreSQL Global Development PGGroup
 *
 * src/include/nodes/lockoptions.h
 *
 *-------------------------------------------------------------------------
 */

namespace duckdb_libpgquery {

/*
 * This enum represents the different strengths of FOR UPDATE/SHARE clauses.
 * The ordering here is important, because the highest numerical value takes
 * precedence when a RTE is specified multiple ways.  See applyLockingClause.
 */
typedef enum PGLockClauseStrength {
	PG_LCS_NONE,           /* no such clause - only used in PGPlanRowMark */
	PG_LCS_FORKEYSHARE,    /* FOR KEY SHARE */
	PG_LCS_FORSHARE,       /* FOR SHARE */
	PG_LCS_FORNOKEYUPDATE, /* FOR NO KEY UPDATE */
	LCS_FORUPDATE          /* FOR UPDATE */
} PGLockClauseStrength;

/*
 * This enum controls how to deal with rows being locked by FOR UPDATE/SHARE
 * clauses (i.e., it represents the NOWAIT and SKIP LOCKED options).
 * The ordering here is important, because the highest numerical value takes
 * precedence when a RTE is specified multiple ways.  See applyLockingClause.
 */
typedef enum PGLockWaitPolicy {
	/* Wait for the lock to become available (default behavior) */
	PGLockWaitBlock,
	/* Skip rows that can't be locked (SKIP LOCKED) */
	PGLockWaitSkip,
	/* Raise an error if a row cannot be locked (NOWAIT) */
	LockWaitError
} PGLockWaitPolicy;

}

// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * primnodes.h
 *	  Definitions for "primitive" node types, those that are used in more
 *	  than one of the parse/plan/execute stages of the query pipeline.
 *	  Currently, these are mostly nodes for executable expressions
 *	  and join trees.
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development PGGroup
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/primnodes.h
 *
 *-------------------------------------------------------------------------
 */




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * attnum.h
 *	  POSTGRES attribute number definitions.
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development PGGroup
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/attnum.h
 *
 *-------------------------------------------------------------------------
 */


#include <cstdint>

/*
 * user defined attribute numbers start at 1.   -ay 2/95
 */
typedef int16_t PGAttrNumber;

#define InvalidAttrNumber		0
#define MaxAttrNumber			32767

/* ----------------
 *		support macros
 * ----------------
 */
/*
 * AttributeNumberIsValid
 *		True iff the attribute number is valid.
 */
#define AttributeNumberIsValid(attributeNumber) \
	((bool) ((attributeNumber) != InvalidAttrNumber))

/*
 * AttrNumberIsForUserDefinedAttr
 *		True iff the attribute number corresponds to an user defined attribute.
 */
#define AttrNumberIsForUserDefinedAttr(attributeNumber) \
	((bool) ((attributeNumber) > 0))

/*
 * AttrNumberGetAttrOffset
 *		Returns the attribute offset for an attribute number.
 *
 * Note:
 *		Assumes the attribute number is for a user defined attribute.
 */
#define AttrNumberGetAttrOffset(attNum) \
( \
	AssertMacro(AttrNumberIsForUserDefinedAttr(attNum)), \
	((attNum) - 1) \
)

/*
 * AttributeOffsetGetAttributeNumber
 *		Returns the attribute number for an attribute offset.
 */
#define AttrOffsetGetAttrNumber(attributeOffset) \
	 ((PGAttrNumber) (1 + (attributeOffset)))


// LICENSE_CHANGE_END




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * pg_list.h
 *	  interface for PostgreSQL generic linked list package
 *
 * This package implements singly-linked homogeneous lists.
 *
 * It is important to have constant-time length, append, and prepend
 * operations. To achieve this, we deal with two distinct data
 * structures:
 *
 *		1. A set of "list cells": each cell contains a data field and
 *		   a link to the next cell in the list or NULL.
 *		2. A single structure containing metadata about the list: the
 *		   type of the list, pointers to the head and tail cells, and
 *		   the length of the list.
 *
 * We support three types of lists:
 *
 *	duckdb_libpgquery::T_PGList: lists of pointers
 *		(in practice usually pointers to Nodes, but not always;
 *		declared as "void *" to minimize casting annoyances)
 *	duckdb_libpgquery::T_PGIntList: lists of integers
 *	duckdb_libpgquery::T_PGOidList: lists of Oids
 *
 * (At the moment, ints and Oids are the same size, but they may not
 * always be so; try to be careful to maintain the distinction.)
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development PGGroup
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/pg_list.h
 *
 *-------------------------------------------------------------------------
 */




// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * nodes.h
 *	  Definitions for tagged nodes.
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development PGGroup
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/nodes.h
 *
 *-------------------------------------------------------------------------
 */




namespace duckdb_libpgquery {

/*
 * The first field of every node is NodeTag. Each node created (with makeNode)
 * will have one of the following tags as the value of its first field.
 *
 * Note that inserting or deleting node types changes the numbers of other
 * node types later in the list.  This is no problem during development, since
 * the node numbers are never stored on disk.  But don't do it in a released
 * branch, because that would represent an ABI break for extensions.
 */
typedef enum PGNodeTag {
	T_PGInvalid = 0,

	/*
	 * TAGS FOR EXECUTOR NODES (execnodes.h)
	 */
	T_PGIndexInfo,
	T_PGExprContext,
	T_PGProjectionInfo,
	T_PGJunkFilter,
	T_PGResultRelInfo,
	T_PGEState,
	T_PGTupleTableSlot,

	/*
	 * TAGS FOR PLAN NODES (plannodes.h)
	 */
	T_PGPlan,
	T_PGResult,
	T_PGProjectSet,
	T_PGModifyTable,
	T_PGAppend,
	T_PGMergeAppend,
	T_PGRecursiveUnion,
	T_PGBitmapAnd,
	T_PGBitmapOr,
	T_PGScan,
	T_PGSeqScan,
	T_PGSampleScan,
	T_PGIndexScan,
	T_PGIndexOnlyScan,
	T_PGBitmapIndexScan,
	T_PGBitmapHeapScan,
	T_PGTidScan,
	T_PGSubqueryScan,
	T_PGFunctionScan,
	T_PGValuesScan,
	T_PGTableFuncScan,
	T_PGCteScan,
	T_PGNamedTuplestoreScan,
	T_PGWorkTableScan,
	T_PGForeignScan,
	T_PGCustomScan,
	T_PGJoin,
	T_PGNestLoop,
	T_PGMergeJoin,
	T_PGHashJoin,
	T_PGMaterial,
	T_PGSort,
	T_PGGroup,
	T_PGAgg,
	T_PGWindowAgg,
	T_PGUnique,
	T_PGGather,
	T_PGGatherMerge,
	T_PGHash,
	T_PGSetOp,
	T_PGLockRows,
	T_PGLimit,
	/* these aren't subclasses of PGPlan: */
	T_PGNestLoopParam,
	T_PGPlanRowMark,
	T_PGPlanInvalItem,

	/*
	 * TAGS FOR PLAN STATE NODES (execnodes.h)
	 *
	 * These should correspond one-to-one with PGPlan node types.
	 */
	T_PGPlanState,
	T_PGResultState,
	T_PGProjectSetState,
	T_PGModifyTableState,
	T_PGAppendState,
	T_PGMergeAppendState,
	T_PGRecursiveUnionState,
	T_PGBitmapAndState,
	T_PGBitmapOrState,
	T_PGScanState,
	T_PGSeqScanState,
	T_PGSampleScanState,
	T_PGIndexScanState,
	T_PGIndexOnlyScanState,
	T_PGBitmapIndexScanState,
	T_PGBitmapHeapScanState,
	T_PGTidScanState,
	T_PGSubqueryScanState,
	T_PGFunctionScanState,
	T_PGTableFuncScanState,
	T_PGValuesScanState,
	T_PGCteScanState,
	T_PGNamedTuplestoreScanState,
	T_PGWorkTableScanState,
	T_PGForeignScanState,
	T_PGCustomScanState,
	T_PGJoinState,
	T_PGNestLoopState,
	T_PGMergeJoinState,
	T_PGHashJoinState,
	T_PGMaterialState,
	T_PGSortState,
	T_PGGroupState,
	T_PGAggState,
	T_PGWindowAggState,
	T_PGUniqueState,
	T_PGGatherState,
	T_PGGatherMergeState,
	T_PGHashState,
	T_PGSetOpState,
	T_PGLockRowsState,
	T_PGLimitState,

	/*
	 * TAGS FOR PRIMITIVE NODES (primnodes.h)
	 */
	T_PGAlias,
	T_PGRangeVar,
	T_PGTableFunc,
	T_PGExpr,
	T_PGVar,
	T_PGConst,
	T_PGParam,
	T_PGAggref,
	T_PGGroupingFunc,
	T_PGWindowFunc,
	T_PGArrayRef,
	T_PGFuncExpr,
	T_PGNamedArgExpr,
	T_PGOpExpr,
	T_PGDistinctExpr,
	T_PGNullIfExpr,
	T_PGScalarArrayOpExpr,
	T_PGBoolExpr,
	T_PGSubLink,
	T_PGSubPlan,
	T_PGAlternativeSubPlan,
	T_PGFieldSelect,
	T_PGFieldStore,
	T_PGRelabelType,
	T_PGCoerceViaIO,
	T_PGArrayCoerceExpr,
	T_PGConvertRowtypeExpr,
	T_PGCollateExpr,
	T_PGCaseExpr,
	T_PGCaseWhen,
	T_PGCaseTestExpr,
	T_PGArrayExpr,
	T_PGRowExpr,
	T_PGRowCompareExpr,
	T_PGCoalesceExpr,
	T_PGMinMaxExpr,
	T_PGSQLValueFunction,
	T_PGXmlExpr,
	T_PGNullTest,
	T_PGBooleanTest,
	T_PGCoerceToDomain,
	T_PGCoerceToDomainValue,
	T_PGSetToDefault,
	T_PGCurrentOfExpr,
	T_PGNextValueExpr,
	T_PGInferenceElem,
	T_PGTargetEntry,
	T_PGRangeTblRef,
	T_PGJoinExpr,
	T_PGFromExpr,
	T_PGOnConflictExpr,
	T_PGIntoClause,
	T_PGLambdaFunction,

	/*
	 * TAGS FOR EXPRESSION STATE NODES (execnodes.h)
	 *
	 * ExprState represents the evaluation state for a whole expression tree.
	 * Most Expr-based plan nodes do not have a corresponding expression state
	 * node, they're fully handled within execExpr* - but sometimes the state
	 * needs to be shared with other parts of the executor, as for example
	 * with AggrefExprState, which nodeAgg.c has to modify.
	 */
	T_PGExprState,
	T_PGAggrefExprState,
	T_PGWindowFuncExprState,
	T_PGSetExprState,
	T_PGSubPlanState,
	T_PGAlternativeSubPlanState,
	T_PGDomainConstraintState,

	/*
	 * TAGS FOR PLANNER NODES (relation.h)
	 */
	T_PGPlannerInfo,
	T_PGPlannerGlobal,
	T_PGRelOptInfo,
	T_PGIndexOptInfo,
	T_PGForeignKeyOptInfo,
	T_PGParamPathInfo,
	T_PGPath,
	T_PGIndexPath,
	T_PGBitmapHeapPath,
	T_PGBitmapAndPath,
	T_PGBitmapOrPath,
	T_PGTidPath,
	T_PGSubqueryScanPath,
	T_PGForeignPath,
	T_PGCustomPath,
	T_PGNestPath,
	T_PGMergePath,
	T_PGHashPath,
	T_PGAppendPath,
	T_PGMergeAppendPath,
	T_PGResultPath,
	T_PGMaterialPath,
	T_PGUniquePath,
	T_PGGatherPath,
	T_PGGatherMergePath,
	T_PGProjectionPath,
	T_PGProjectSetPath,
	T_PGSortPath,
	T_PGGroupPath,
	T_PGUpperUniquePath,
	T_PGAggPath,
	T_PGGroupingSetsPath,
	T_PGMinMaxAggPath,
	T_PGWindowAggPath,
	T_PGSetOpPath,
	T_PGRecursiveUnionPath,
	T_PGLockRowsPath,
	T_PGModifyTablePath,
	T_PGLimitPath,
	/* these aren't subclasses of Path: */
	T_PGEquivalenceClass,
	T_PGEquivalenceMember,
	T_PGPathKey,
	T_PGPathTarget,
	T_PGRestrictInfo,
	T_PGPlaceHolderVar,
	T_PGSpecialJoinInfo,
	T_PGAppendRelInfo,
	T_PGPartitionedChildRelInfo,
	T_PGPlaceHolderInfo,
	T_PGMinMaxAggInfo,
	T_PGPlannerParamItem,
	T_PGRollupData,
	T_PGGroupingSetData,
	T_PGStatisticExtInfo,

	/*
	 * TAGS FOR MEMORY NODES (memnodes.h)
	 */
	T_PGMemoryContext,
	T_PGAllocSetContext,
	T_PGSlabContext,

	/*
	 * TAGS FOR VALUE NODES (value.h)
	 */
	T_PGValue,
	T_PGInteger,
	T_PGFloat,
	T_PGString,
	T_PGBitString,
	T_PGNull,

	/*
	 * TAGS FOR LIST NODES (pg_list.h)
	 */
	T_PGList,
	T_PGIntList,
	T_PGOidList,

	/*
	 * TAGS FOR EXTENSIBLE NODES (extensible.h)
	 */
	T_PGExtensibleNode,

	/*
	 * TAGS FOR STATEMENT NODES (mostly in parsenodes.h)
	 */
	T_PGRawStmt,
	T_PGQuery,
	T_PGPlannedStmt,
	T_PGInsertStmt,
	T_PGDeleteStmt,
	T_PGUpdateStmt,
	T_PGSelectStmt,
	T_PGAlterTableStmt,
	T_PGAlterTableCmd,
	T_PGAlterDomainStmt,
	T_PGSetOperationStmt,
	T_PGGrantStmt,
	T_PGGrantRoleStmt,
	T_PGAlterDefaultPrivilegesStmt,
	T_PGClosePortalStmt,
	T_PGClusterStmt,
	T_PGCopyStmt,
	T_PGCreateStmt,
	T_PGDefineStmt,
	T_PGDropStmt,
	T_PGTruncateStmt,
	T_PGCommentStmt,
	T_PGFetchStmt,
	T_PGIndexStmt,
	T_PGCreateFunctionStmt,
	T_PGAlterFunctionStmt,
	T_PGDoStmt,
	T_PGRenameStmt,
	T_PGRuleStmt,
	T_PGNotifyStmt,
	T_PGListenStmt,
	T_PGUnlistenStmt,
	T_PGTransactionStmt,
	T_PGViewStmt,
	T_PGLoadStmt,
	T_PGCreateDomainStmt,
	T_PGCreatedbStmt,
	T_PGDropdbStmt,
	T_PGVacuumStmt,
	T_PGExplainStmt,
	T_PGCreateTableAsStmt,
	T_PGCreateSeqStmt,
	T_PGAlterSeqStmt,
	T_PGVariableSetStmt,
	T_PGVariableShowStmt,
	T_PGVariableShowSelectStmt,
	T_PGDiscardStmt,
	T_PGCreateTrigStmt,
	T_PGCreatePLangStmt,
	T_PGCreateRoleStmt,
	T_PGAlterRoleStmt,
	T_PGDropRoleStmt,
	T_PGLockStmt,
	T_PGConstraintsSetStmt,
	T_PGReindexStmt,
	T_PGCheckPointStmt,
	T_PGCreateSchemaStmt,
	T_PGAlterDatabaseStmt,
	T_PGAlterDatabaseSetStmt,
	T_PGAlterRoleSetStmt,
	T_PGCreateConversionStmt,
	T_PGCreateCastStmt,
	T_PGCreateOpClassStmt,
	T_PGCreateOpFamilyStmt,
	T_PGAlterOpFamilyStmt,
	T_PGPrepareStmt,
	T_PGExecuteStmt,
	T_PGCallStmt,
	T_PGDeallocateStmt,
	T_PGDeclareCursorStmt,
	T_PGCreateTableSpaceStmt,
	T_PGDropTableSpaceStmt,
	T_PGAlterObjectDependsStmt,
	T_PGAlterObjectSchemaStmt,
	T_PGAlterOwnerStmt,
	T_PGAlterOperatorStmt,
	T_PGDropOwnedStmt,
	T_PGReassignOwnedStmt,
	T_PGCompositeTypeStmt,
	T_PGCreateTypeStmt,
	T_PGCreateRangeStmt,
	T_PGAlterEnumStmt,
	T_PGAlterTSDictionaryStmt,
	T_PGAlterTSConfigurationStmt,
	T_PGCreateFdwStmt,
	T_PGAlterFdwStmt,
	T_PGCreateForeignServerStmt,
	T_PGAlterForeignServerStmt,
	T_PGCreateUserMappingStmt,
	T_PGAlterUserMappingStmt,
	T_PGDropUserMappingStmt,
	T_PGAlterTableSpaceOptionsStmt,
	T_PGAlterTableMoveAllStmt,
	T_PGSecLabelStmt,
	T_PGCreateForeignTableStmt,
	T_PGImportForeignSchemaStmt,
	T_PGCreateExtensionStmt,
	T_PGAlterExtensionStmt,
	T_PGAlterExtensionContentsStmt,
	T_PGCreateEventTrigStmt,
	T_PGAlterEventTrigStmt,
	T_PGRefreshMatViewStmt,
	T_PGReplicaIdentityStmt,
	T_PGAlterSystemStmt,
	T_PGCreatePolicyStmt,
	T_PGAlterPolicyStmt,
	T_PGCreateTransformStmt,
	T_PGCreateAmStmt,
	T_PGCreatePublicationStmt,
	T_PGAlterPublicationStmt,
	T_PGCreateSubscriptionStmt,
	T_PGAlterSubscriptionStmt,
	T_PGDropSubscriptionStmt,
	T_PGCreateStatsStmt,
	T_PGAlterCollationStmt,
	T_PGPragmaStmt,
	T_PGExportStmt,
	T_PGImportStmt,

	/*
	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
	 */
	T_PGAExpr,
	T_PGColumnRef,
	T_PGParamRef,
	T_PGAConst,
	T_PGFuncCall,
	T_PGAStar,
	T_PGAIndices,
	T_PGAIndirection,
	T_PGAArrayExpr,
	T_PGResTarget,
	T_PGMultiAssignRef,
	T_PGTypeCast,
	T_PGCollateClause,
	T_PGSortBy,
	T_PGWindowDef,
	T_PGRangeSubselect,
	T_PGRangeFunction,
	T_PGRangeTableSample,
	T_PGRangeTableFunc,
	T_PGRangeTableFuncCol,
	T_PGTypeName,
	T_PGColumnDef,
	T_PGIndexElem,
	T_PGConstraint,
	T_PGDefElem,
	T_PGRangeTblEntry,
	T_PGRangeTblFunction,
	T_PGTableSampleClause,
	T_PGWithCheckOption,
	T_PGSortGroupClause,
	T_PGGroupingSet,
	T_PGWindowClause,
	T_PGObjectWithArgs,
	T_PGAccessPriv,
	T_PGCreateOpClassItem,
	T_PGTableLikeClause,
	T_PGFunctionParameter,
	T_PGLockingClause,
	T_PGRowMarkClause,
	T_PGXmlSerialize,
	T_PGWithClause,
	T_PGInferClause,
	T_PGOnConflictClause,
	T_PGCommonTableExpr,
	T_PGRoleSpec,
	T_PGTriggerTransition,
	T_PGPartitionElem,
	T_PGPartitionSpec,
	T_PGPartitionBoundSpec,
	T_PGPartitionRangeDatum,
	T_PGPartitionCmd,
	T_PGIntervalConstant,
	T_PGSampleSize,
	T_PGSampleOptions,
	T_PGLimitPercent,
	T_PGPositionalReference,

	/*
	 * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
	 */
	T_PGIdentifySystemCmd,
	T_PGBaseBackupCmd,
	T_PGCreateReplicationSlotCmd,
	T_PGDropReplicationSlotCmd,
	T_PGStartReplicationCmd,
	T_PGTimeLineHistoryCmd,
	T_PGSQLCmd,

	/*
	 * TAGS FOR RANDOM OTHER STUFF
	 *
	 * These are objects that aren't part of parse/plan/execute node tree
	 * structures, but we give them NodeTags anyway for identification
	 * purposes (usually because they are involved in APIs where we want to
	 * pass multiple object types through the same pointer).
	 */
	T_PGTriggerData,        /* in commands/trigger.h */
	T_PGEventTriggerData,   /* in commands/event_trigger.h */
	T_PGReturnSetInfo,      /* in nodes/execnodes.h */
	T_PGWindowObjectData,   /* private in nodeWindowAgg.c */
	T_PGTIDBitmap,          /* in nodes/tidbitmap.h */
	T_PGInlineCodeBlock,    /* in nodes/parsenodes.h */
	T_PGFdwRoutine,         /* in foreign/fdwapi.h */
	T_PGIndexAmRoutine,     /* in access/amapi.h */
	T_PGTsmRoutine,         /* in access/tsmapi.h */
	T_PGForeignKeyCacheInfo /* in utils/rel.h */
} PGNodeTag;

/*
 * The first field of a node of any type is guaranteed to be the NodeTag.
 * Hence the type of any node can be gotten by casting it to Node. Declaring
 * a variable to be of PGNode * (instead of void *) can also facilitate
 * debugging.
 */
typedef struct PGNode {
	PGNodeTag type;
} PGNode;

#define nodeTag(nodeptr) (((const PGNode *)(nodeptr))->type)

#define makeNode(_type_) ((_type_ *)newNode(sizeof(_type_), T_##_type_))

#define NodeSetTag(nodeptr, t) (((PGNode *)(nodeptr))->type = (t))

#define IsA(nodeptr, _type_) (nodeTag(nodeptr) == T_##_type_)

/*
 * castNode(type, ptr) casts ptr to "type *", and if assertions are enabled,
 * verifies that the node has the appropriate type (using its nodeTag()).
 *
 * Use an inline function when assertions are enabled, to avoid multiple
 * evaluations of the ptr argument (which could e.g. be a function call).
 */
#ifdef USE_ASSERT_CHECKING
static inline PGNode *castNodeImpl(PGNodeTag type, void *ptr) {
	Assert(ptr == NULL || nodeTag(ptr) == type);
	return (PGNode *)ptr;
}
#define castNode(_type_, nodeptr) ((_type_ *)castNodeImpl(T_##_type_, nodeptr))
#else
#define castNode(_type_, nodeptr) ((_type_ *)(nodeptr))
#endif /* USE_ASSERT_CHECKING */

/* ----------------------------------------------------------------
 *					  extern declarations follow
 * ----------------------------------------------------------------
 */

/*
 * nodes/{outfuncs.c,print.c}
 */
struct PGBitmapset;      /* not to include bitmapset.h here */
struct PGStringInfoData; /* not to include stringinfo.h here */

PGNode* newNode(size_t size, PGNodeTag type);

void outNode(struct PGStringInfoData *str, const void *obj);
void outToken(struct PGStringInfoData *str, const char *s);
void outBitmapset(struct PGStringInfoData *str, const struct PGBitmapset *bms);
void outDatum(struct PGStringInfoData *str, uintptr_t value, int typlen, bool typbyval);
char *nodeToString(const void *obj);
char *bmsToString(const struct PGBitmapset *bms);

/*
 * nodes/{readfuncs.c,read.c}
 */
void *stringToNode(char *str);
struct PGBitmapset *readBitmapset(void);
uintptr_t readDatum(bool typbyval);
bool *readBoolCols(int numCols);
int *readIntCols(int numCols);
PGOid *readOidCols(int numCols);
int16_t *readAttrNumberCols(int numCols);

/*
 * nodes/copyfuncs.c
 */
void *copyObjectImpl(const void *obj);

/* cast result back to argument type, if supported by compiler */
//#ifdef HAVE_TYPEOF
//#define copyObject(obj) ((typeof(obj)) copyObjectImpl(obj))
//#else
//#define copyObject(obj) copyObjectImpl(obj)
//#endif

/*
 * nodes/equalfuncs.c
 */
// extern bool equal(const void *a, const void *b);

/*
 * Typedefs for identifying qualifier selectivities and plan costs as such.
 * These are just plain "double"s, but declaring a variable as Selectivity
 * or Cost makes the intent more obvious.
 *
 * These could have gone into plannodes.h or some such, but many files
 * depend on them...
 */
typedef double Selectivity; /* fraction of tuples a qualifier will pass */
typedef double Cost;        /* execution cost (in page-access units) */

/*
 * PGCmdType -
 *	  enums for type of operation represented by a PGQuery or PGPlannedStmt
 *
 * This is needed in both parsenodes.h and plannodes.h, so put it here...
 */
typedef enum PGCmdType {
	PG_CMD_UNKNOWN,
	PG_CMD_SELECT, /* select stmt */
	PG_CMD_UPDATE, /* update stmt */
	PG_CMD_INSERT, /* insert stmt */
	PG_CMD_DELETE,
	PG_CMD_UTILITY, /* cmds like create, destroy, copy, vacuum,
								 * etc. */
	PG_CMD_NOTHING  /* dummy command for instead nothing rules
								 * with qual */
} PGCmdType;

/*
 * PGJoinType -
 *	  enums for types of relation joins
 *
 * PGJoinType determines the exact semantics of joining two relations using
 * a matching qualification.  For example, it tells what to do with a tuple
 * that has no match in the other relation.
 *
 * This is needed in both parsenodes.h and plannodes.h, so put it here...
 */
typedef enum PGJoinType {
	/*
	 * The canonical kinds of joins according to the SQL JOIN syntax. Only
	 * these codes can appear in parser output (e.g., PGJoinExpr nodes).
	 */
	PG_JOIN_INNER, /* matching tuple pairs only */
	PG_JOIN_LEFT,  /* pairs + unmatched LHS tuples */
	PG_JOIN_FULL,  /* pairs + unmatched LHS + unmatched RHS */
	PG_JOIN_RIGHT, /* pairs + unmatched RHS tuples */

	/*
	 * Semijoins and anti-semijoins (as defined in relational theory) do not
	 * appear in the SQL JOIN syntax, but there are standard idioms for
	 * representing them (e.g., using EXISTS).  The planner recognizes these
	 * cases and converts them to joins.  So the planner and executor must
	 * support these codes.  NOTE: in PG_JOIN_SEMI output, it is unspecified
	 * which matching RHS row is joined to.  In PG_JOIN_ANTI output, the row is
	 * guaranteed to be null-extended.
	 */
	PG_JOIN_SEMI, /* 1 copy of each LHS row that has match(es) */
	PG_JOIN_ANTI, /* 1 copy of each LHS row that has no match */

	/*
	 * These codes are used internally in the planner, but are not supported
	 * by the executor (nor, indeed, by most of the planner).
	 */
	PG_JOIN_UNIQUE_OUTER, /* LHS path must be made unique */
	PG_JOIN_UNIQUE_INNER  /* RHS path must be made unique */

	/*
	 * We might need additional join types someday.
	 */
} PGJoinType;

/*
 * OUTER joins are those for which pushed-down quals must behave differently
 * from the join's own quals.  This is in fact everything except INNER and
 * SEMI joins.  However, this macro must also exclude the JOIN_UNIQUE symbols
 * since those are temporary proxies for what will eventually be an INNER
 * join.
 *
 * Note: semijoins are a hybrid case, but we choose to treat them as not
 * being outer joins.  This is okay principally because the SQL syntax makes
 * it impossible to have a pushed-down qual that refers to the inner relation
 * of a semijoin; so there is no strong need to distinguish join quals from
 * pushed-down quals.  This is convenient because for almost all purposes,
 * quals attached to a semijoin can be treated the same as innerjoin quals.
 */
#define IS_OUTER_JOIN(jointype) \
	(((1 << (jointype)) & ((1 << PG_JOIN_LEFT) | (1 << PG_JOIN_FULL) | (1 << PG_JOIN_RIGHT) | (1 << PG_JOIN_ANTI))) != 0)

/*
 * PGAggStrategy -
 *	  overall execution strategies for PGAgg plan nodes
 *
 * This is needed in both plannodes.h and relation.h, so put it here...
 */
typedef enum PGAggStrategy {
	PG_AGG_PLAIN,  /* simple agg across all input rows */
	PG_AGG_SORTED, /* grouped agg, input must be sorted */
	PG_AGG_HASHED, /* grouped agg, use internal hashtable */
	AGG_MIXED      /* grouped agg, hash and sort both used */
} PGAggStrategy;

/*
 * PGAggSplit -
 *	  splitting (partial aggregation) modes for PGAgg plan nodes
 *
 * This is needed in both plannodes.h and relation.h, so put it here...
 */

/* Primitive options supported by nodeAgg.c: */
#define AGGSPLITOP_COMBINE 0x01 /* substitute combinefn for transfn */
#define AGGSPLITOP_SKIPFINAL 0x02 /* skip finalfn, return state as-is */
#define AGGSPLITOP_SERIALIZE 0x04 /* apply serializefn to output */
#define AGGSPLITOP_DESERIALIZE 0x08 /* apply deserializefn to input */

/* Supported operating modes (i.e., useful combinations of these options): */
typedef enum PGAggSplit {
	/* Basic, non-split aggregation: */
	PG_AGGSPLIT_SIMPLE = 0,
	/* Initial phase of partial aggregation, with serialization: */
	PG_AGGSPLIT_INITIAL_SERIAL = AGGSPLITOP_SKIPFINAL | AGGSPLITOP_SERIALIZE,
	/* Final phase of partial aggregation, with deserialization: */
	PG_AGGSPLIT_FINAL_DESERIAL = AGGSPLITOP_COMBINE | AGGSPLITOP_DESERIALIZE
} PGAggSplit;

/* Test whether an PGAggSplit value selects each primitive option: */
#define DO_AGGSPLIT_COMBINE(as) (((as)&AGGSPLITOP_COMBINE) != 0)
#define DO_AGGSPLIT_SKIPFINAL(as) (((as)&AGGSPLITOP_SKIPFINAL) != 0)
#define DO_AGGSPLIT_SERIALIZE(as) (((as)&AGGSPLITOP_SERIALIZE) != 0)
#define DO_AGGSPLIT_DESERIALIZE(as) (((as)&AGGSPLITOP_DESERIALIZE) != 0)

/*
 * PGSetOpCmd and PGSetOpStrategy -
 *	  overall semantics and execution strategies for PGSetOp plan nodes
 *
 * This is needed in both plannodes.h and relation.h, so put it here...
 */
typedef enum PGSetOpCmd {
	PG_SETOPCMD_INTERSECT,
	PG_SETOPCMD_INTERSECT_ALL,
	PG_SETOPCMD_EXCEPT,
	PG_SETOPCMD_EXCEPT_ALL
} PGSetOpCmd;

typedef enum PGSetOpStrategy {
	PG_SETOP_SORTED, /* input must be sorted */
	PG_SETOP_HASHED  /* use internal hashtable */
} PGSetOpStrategy;

/*
 * PGOnConflictAction -
 *	  "ON CONFLICT" clause type of query
 *
 * This is needed in both parsenodes.h and plannodes.h, so put it here...
 */
typedef enum PGOnConflictAction {
	PG_ONCONFLICT_NONE,    /* No "ON CONFLICT" clause */
	PG_ONCONFLICT_NOTHING, /* ON CONFLICT ... DO NOTHING */
	PG_ONCONFLICT_UPDATE   /* ON CONFLICT ... DO UPDATE */
} PGOnConflictAction;

}


// LICENSE_CHANGE_END


namespace duckdb_libpgquery {

typedef struct PGListCell ListCell;

typedef struct PGList {
	PGNodeTag		type;			/* duckdb_libpgquery::T_PGList, duckdb_libpgquery::T_PGIntList, or duckdb_libpgquery::T_PGOidList */
	int			length;
	PGListCell   *head;
	PGListCell   *tail;
} PGList;

struct PGListCell {
	union
	{
		void	   *ptr_value;
		int			int_value;
		PGOid			oid_value;
	}			data;
	PGListCell   *next;
};

/*
 * The *only* valid representation of an empty list is NIL; in other
 * words, a non-NIL list is guaranteed to have length >= 1 and
 * head/tail != NULL
 */
#define NIL						((PGList *) NULL)

/*
 * These routines are used frequently. However, we can't implement
 * them as macros, since we want to avoid double-evaluation of macro
 * arguments.
 */
static inline PGListCell *
list_head(const PGList *l)
{
	return l ? l->head : NULL;
}

static inline PGListCell *
list_tail(PGList *l)
{
	return l ? l->tail : NULL;
}

static inline int
list_length(const PGList *l)
{
	return l ? l->length : 0;
}

/*
 * NB: There is an unfortunate legacy from a previous incarnation of
 * the PGList API: the macro lfirst() was used to mean "the data in this
 * cons cell". To avoid changing every usage of lfirst(), that meaning
 * has been kept. As a result, lfirst() takes a PGListCell and returns
 * the data it contains; to get the data in the first cell of a
 * PGList, use linitial(). Worse, lsecond() is more closely related to
 * linitial() than lfirst(): given a PGList, lsecond() returns the data
 * in the second cons cell.
 */

#define lnext(lc)				((lc)->next)
#define lfirst(lc)				((lc)->data.ptr_value)
#define lfirst_int(lc)			((lc)->data.int_value)
#define lfirst_oid(lc)			((lc)->data.oid_value)
#define lfirst_node(type,lc)	castNode(type, lfirst(lc))

#define linitial(l)				lfirst(list_head(l))
#define linitial_int(l)			lfirst_int(list_head(l))
#define linitial_oid(l)			lfirst_oid(list_head(l))
#define linitial_node(type,l)	castNode(type, linitial(l))

#define lsecond(l)				lfirst(lnext(list_head(l)))
#define lsecond_int(l)			lfirst_int(lnext(list_head(l)))
#define lsecond_oid(l)			lfirst_oid(lnext(list_head(l)))
#define lsecond_node(type,l)	castNode(type, lsecond(l))

#define lthird(l)				lfirst(lnext(lnext(list_head(l))))
#define lthird_int(l)			lfirst_int(lnext(lnext(list_head(l))))
#define lthird_oid(l)			lfirst_oid(lnext(lnext(list_head(l))))
#define lthird_node(type,l)		castNode(type, lthird(l))

#define lfourth(l)				lfirst(lnext(lnext(lnext(list_head(l)))))
#define lfourth_int(l)			lfirst_int(lnext(lnext(lnext(list_head(l)))))
#define lfourth_oid(l)			lfirst_oid(lnext(lnext(lnext(list_head(l)))))
#define lfourth_node(type,l)	castNode(type, lfourth(l))

#define llast(l)				lfirst(list_tail(l))
#define llast_int(l)			lfirst_int(list_tail(l))
#define llast_oid(l)			lfirst_oid(list_tail(l))
#define llast_node(type,l)		castNode(type, llast(l))

/*
 * Convenience macros for building fixed-length lists
 */
#define list_make1(x1)				lcons(x1, NIL)
#define list_make2(x1,x2)			lcons(x1, list_make1(x2))
#define list_make3(x1,x2,x3)		lcons(x1, list_make2(x2, x3))
#define list_make4(x1,x2,x3,x4)		lcons(x1, list_make3(x2, x3, x4))
#define list_make5(x1,x2,x3,x4,x5)	lcons(x1, list_make4(x2, x3, x4, x5))

#define list_make1_int(x1)			lcons_int(x1, NIL)
#define list_make2_int(x1,x2)		lcons_int(x1, list_make1_int(x2))
#define list_make3_int(x1,x2,x3)	lcons_int(x1, list_make2_int(x2, x3))
#define list_make4_int(x1,x2,x3,x4) lcons_int(x1, list_make3_int(x2, x3, x4))
#define list_make5_int(x1,x2,x3,x4,x5)	lcons_int(x1, list_make4_int(x2, x3, x4, x5))

#define list_make1_oid(x1)			lcons_oid(x1, NIL)
#define list_make2_oid(x1,x2)		lcons_oid(x1, list_make1_oid(x2))
#define list_make3_oid(x1,x2,x3)	lcons_oid(x1, list_make2_oid(x2, x3))
#define list_make4_oid(x1,x2,x3,x4) lcons_oid(x1, list_make3_oid(x2, x3, x4))
#define list_make5_oid(x1,x2,x3,x4,x5)	lcons_oid(x1, list_make4_oid(x2, x3, x4, x5))

/*
 * foreach -
 *	  a convenience macro which loops through the list
 */
#define foreach(cell, l)	\
	for ((cell) = list_head(l); (cell) != NULL; (cell) = lnext(cell))

/*
 * for_each_cell -
 *	  a convenience macro which loops through a list starting from a
 *	  specified cell
 */
#define for_each_cell(cell, initcell)	\
	for ((cell) = (initcell); (cell) != NULL; (cell) = lnext(cell))

/*
 * forboth -
 *	  a convenience macro for advancing through two linked lists
 *	  simultaneously. This macro loops through both lists at the same
 *	  time, stopping when either list runs out of elements. Depending
 *	  on the requirements of the call site, it may also be wise to
 *	  assert that the lengths of the two lists are equal.
 */
#define forboth(cell1, list1, cell2, list2)							\
	for ((cell1) = list_head(list1), (cell2) = list_head(list2);	\
		 (cell1) != NULL && (cell2) != NULL;						\
		 (cell1) = lnext(cell1), (cell2) = lnext(cell2))

/*
 * for_both_cell -
 *	  a convenience macro which loops through two lists starting from the
 *	  specified cells of each. This macro loops through both lists at the same
 *	  time, stopping when either list runs out of elements.  Depending on the
 *	  requirements of the call site, it may also be wise to assert that the
 *	  lengths of the two lists are equal, and initcell1 and initcell2 are at
 *	  the same position in the respective lists.
 */
#define for_both_cell(cell1, initcell1, cell2, initcell2)	\
	for ((cell1) = (initcell1), (cell2) = (initcell2);		\
		 (cell1) != NULL && (cell2) != NULL;				\
		 (cell1) = lnext(cell1), (cell2) = lnext(cell2))

/*
 * forthree -
 *	  the same for three lists
 */
#define forthree(cell1, list1, cell2, list2, cell3, list3)			\
	for ((cell1) = list_head(list1), (cell2) = list_head(list2), (cell3) = list_head(list3); \
		 (cell1) != NULL && (cell2) != NULL && (cell3) != NULL;		\
		 (cell1) = lnext(cell1), (cell2) = lnext(cell2), (cell3) = lnext(cell3))

PGList *lappend(PGList *list, void *datum);
PGList *lappend_int(PGList *list, int datum);
PGList *lappend_oid(PGList *list, PGOid datum);

PGListCell *lappend_cell(PGList *list, PGListCell *prev, void *datum);
PGListCell *lappend_cell_int(PGList *list, PGListCell *prev, int datum);
PGListCell *lappend_cell_oid(PGList *list, PGListCell *prev, PGOid datum);

PGList *lcons(void *datum, PGList *list);
PGList *lcons_int(int datum, PGList *list);
PGList *lcons_oid(PGOid datum, PGList *list);

PGList *list_concat(PGList *list1, PGList *list2);
PGList *list_truncate(PGList *list, int new_size);

PGListCell *list_nth_cell(const PGList *list, int n);
void *list_nth(const PGList *list, int n);
int	list_nth_int(const PGList *list, int n);
PGOid	list_nth_oid(const PGList *list, int n);
#define list_nth_node(type,list,n)	castNode(type, list_nth(list, n))

bool list_member(const PGList *list, const void *datum);
bool list_member_ptr(const PGList *list, const void *datum);
bool list_member_int(const PGList *list, int datum);
bool list_member_oid(const PGList *list, PGOid datum);

PGList *list_delete(PGList *list, void *datum);
PGList *list_delete_ptr(PGList *list, void *datum);
PGList *list_delete_int(PGList *list, int datum);
PGList *list_delete_oid(PGList *list, PGOid datum);
PGList *list_delete_first(PGList *list);
PGList *list_delete_cell(PGList *list, PGListCell *cell, PGListCell *prev);

PGList *list_union(const PGList *list1, const PGList *list2);
PGList *list_union_ptr(const PGList *list1, const PGList *list2);
PGList *list_union_int(const PGList *list1, const PGList *list2);
PGList *list_union_oid(const PGList *list1, const PGList *list2);

PGList *list_intersection(const PGList *list1, const PGList *list2);
PGList *list_intersection_int(const PGList *list1, const PGList *list2);

/* currently, there's no need for list_intersection_ptr etc */

PGList *list_difference(const PGList *list1, const PGList *list2);
PGList *list_difference_ptr(const PGList *list1, const PGList *list2);
PGList *list_difference_int(const PGList *list1, const PGList *list2);
PGList *list_difference_oid(const PGList *list1, const PGList *list2);

PGList *list_append_unique(PGList *list, void *datum);
PGList *list_append_unique_ptr(PGList *list, void *datum);
PGList *list_append_unique_int(PGList *list, int datum);
PGList *list_append_unique_oid(PGList *list, PGOid datum);

PGList *list_concat_unique(PGList *list1, PGList *list2);
PGList *list_concat_unique_ptr(PGList *list1, PGList *list2);
PGList *list_concat_unique_int(PGList *list1, PGList *list2);
PGList *list_concat_unique_oid(PGList *list1, PGList *list2);

void list_free(PGList *list);
void list_free_deep(PGList *list);

PGList *list_copy(const PGList *list);
PGList *list_copy_tail(const PGList *list, int nskip);

/*
 * To ease migration to the new list API, a set of compatibility
 * macros are provided that reduce the impact of the list API changes
 * as far as possible. Until client code has been rewritten to use the
 * new list API, the ENABLE_LIST_COMPAT symbol can be defined before
 * including pg_list.h
 */
#ifdef ENABLE_LIST_COMPAT

#define lfirsti(lc)					lfirst_int(lc)
#define lfirsto(lc)					lfirst_oid(lc)

#define makeList1(x1)				list_make1(x1)
#define makeList2(x1, x2)			list_make2(x1, x2)
#define makeList3(x1, x2, x3)		list_make3(x1, x2, x3)
#define makeList4(x1, x2, x3, x4)	list_make4(x1, x2, x3, x4)

#define makeListi1(x1)				list_make1_int(x1)
#define makeListi2(x1, x2)			list_make2_int(x1, x2)

#define makeListo1(x1)				list_make1_oid(x1)
#define makeListo2(x1, x2)			list_make2_oid(x1, x2)

#define lconsi(datum, list)			lcons_int(datum, list)
#define lconso(datum, list)			lcons_oid(datum, list)

#define lappendi(list, datum)		lappend_int(list, datum)
#define lappendo(list, datum)		lappend_oid(list, datum)

#define nconc(l1, l2)				list_concat(l1, l2)

#define nth(n, list)				list_nth(list, n)

#define member(datum, list)			list_member(list, datum)
#define ptrMember(datum, list)		list_member_ptr(list, datum)
#define intMember(datum, list)		list_member_int(list, datum)
#define oidMember(datum, list)		list_member_oid(list, datum)

/*
 * Note that the old lremove() determined equality via pointer
 * comparison, whereas the new list_delete() uses equal(); in order to
 * keep the same behavior, we therefore need to map lremove() calls to
 * list_delete_ptr() rather than list_delete()
 */
#define lremove(elem, list)			list_delete_ptr(list, elem)
#define LispRemove(elem, list)		list_delete(list, elem)
#define lremovei(elem, list)		list_delete_int(list, elem)
#define lremoveo(elem, list)		list_delete_oid(list, elem)

#define ltruncate(n, list)			list_truncate(list, n)

#define set_union(l1, l2)			list_union(l1, l2)
#define set_uniono(l1, l2)			list_union_oid(l1, l2)
#define set_ptrUnion(l1, l2)		list_union_ptr(l1, l2)

#define set_difference(l1, l2)		list_difference(l1, l2)
#define set_differenceo(l1, l2)		list_difference_oid(l1, l2)
#define set_ptrDifference(l1, l2)	list_difference_ptr(l1, l2)

#define equali(l1, l2)				equal(l1, l2)
#define equalo(l1, l2)				equal(l1, l2)

#define freeList(list)				list_free(list)

#define listCopy(list)				list_copy(list)

int	length(PGList *list);
#endif							/* ENABLE_LIST_COMPAT */

}

// LICENSE_CHANGE_END


namespace duckdb_libpgquery {

/* ----------------------------------------------------------------
 *						node definitions
 * ----------------------------------------------------------------
 */

/*
 * PGAlias -
 *	  specifies an alias for a range variable; the alias might also
 *	  specify renaming of columns within the table.
 *
 * Note: colnames is a list of PGValue nodes (always strings).  In PGAlias structs
 * associated with RTEs, there may be entries corresponding to dropped
 * columns; these are normally empty strings ("").  See parsenodes.h for info.
 */
typedef struct PGAlias {
	PGNodeTag type;
	char *aliasname;  /* aliased rel name (never qualified) */
	PGList *colnames; /* optional list of column aliases */
} PGAlias;

/* What to do at commit time for temporary relations */
typedef enum PGOnCommitAction {
	PG_ONCOMMIT_NOOP,          /* No ON COMMIT clause (do nothing) */
	PG_ONCOMMIT_PRESERVE_ROWS, /* ON COMMIT PRESERVE ROWS (do nothing) */
	PG_ONCOMMIT_DELETE_ROWS,   /* ON COMMIT DELETE ROWS */
	ONCOMMIT_DROP              /* ON COMMIT DROP */
} PGOnCommitAction;

/* What to do at commit time for temporary relations */
typedef enum PGOnCreateConflict {
	// Standard: throw error
	PG_ERROR_ON_CONFLICT,
	// CREATE IF NOT EXISTS, silently do nothing on conflict
	PG_IGNORE_ON_CONFLICT,
	// CREATE OR REPLACE
	PG_REPLACE_ON_CONFLICT
} PGOnCreateConflict;

/*
 * PGRangeVar - range variable, used in FROM clauses
 *
 * Also used to represent table names in utility statements; there, the alias
 * field is not used, and inh tells whether to apply the operation
 * recursively to child tables.  In some contexts it is also useful to carry
 * a TEMP table indication here.
 */
typedef struct PGRangeVar {
	PGNodeTag type;
	char *catalogname;   /* the catalog (database) name, or NULL */
	char *schemaname;    /* the schema name, or NULL */
	char *relname;       /* the relation/sequence name */
	bool inh;            /* expand rel by inheritance? recursively act
								 * on children? */
	char relpersistence; /* see RELPERSISTENCE_* in pg_class.h */
	PGAlias *alias;      /* table alias & optional column aliases */
	int location;        /* token location, or -1 if unknown */
	PGNode *sample;      /* sample, if any */
} PGRangeVar;

/*
 * PGTableFunc - node for a table function, such as XMLTABLE.
 */
typedef struct PGTableFunc {
	PGNodeTag type;
	PGList *ns_uris;       /* list of namespace uri */
	PGList *ns_names;      /* list of namespace names */
	PGNode *docexpr;       /* input document expression */
	PGNode *rowexpr;       /* row filter expression */
	PGList *colnames;      /* column names (list of String) */
	PGList *coltypes;      /* OID list of column type OIDs */
	PGList *coltypmods;    /* integer list of column typmods */
	PGList *colcollations; /* OID list of column collation OIDs */
	PGList *colexprs;      /* list of column filter expressions */
	PGList *coldefexprs;   /* list of column default expressions */
	PGBitmapset *notnulls; /* nullability flag for each output column */
	int ordinalitycol;     /* counts from 0; -1 if none specified */
	int location;          /* token location, or -1 if unknown */
} PGTableFunc;

/*
 * PGIntoClause - target information for SELECT INTO, CREATE TABLE AS, and
 * CREATE MATERIALIZED VIEW
 *
 * For CREATE MATERIALIZED VIEW, viewQuery is the parsed-but-not-rewritten
 * SELECT PGQuery for the view; otherwise it's NULL.  (Although it's actually
 * PGQuery*, we declare it as PGNode* to avoid a forward reference.)
 */
typedef struct PGIntoClause {
	PGNodeTag type;

	PGRangeVar *rel;           /* target relation name */
	PGList *colNames;          /* column names to assign, or NIL */
	PGList *options;           /* options from WITH clause */
	PGOnCommitAction onCommit; /* what do we do at COMMIT? */
	char *tableSpaceName;      /* table space to use, or NULL */
	PGNode *viewQuery;         /* materialized view's SELECT query */
	bool skipData;             /* true for WITH NO DATA */
} PGIntoClause;

/* ----------------------------------------------------------------
 *					node types for executable expressions
 * ----------------------------------------------------------------
 */

/*
 * PGExpr - generic superclass for executable-expression nodes
 *
 * All node types that are used in executable expression trees should derive
 * from PGExpr (that is, have PGExpr as their first field).  Since PGExpr only
 * contains PGNodeTag, this is a formality, but it is an easy form of
 * documentation.  See also the ExprState node types in execnodes.h.
 */
typedef struct PGExpr {
	PGNodeTag type;
} PGExpr;

/*
 * PGVar - expression node representing a variable (ie, a table column)
 *
 * Note: during parsing/planning, varnoold/varoattno are always just copies
 * of varno/varattno.  At the tail end of planning, PGVar nodes appearing in
 * upper-level plan nodes are reassigned to point to the outputs of their
 * subplans; for example, in a join node varno becomes INNER_VAR or OUTER_VAR
 * and varattno becomes the index of the proper element of that subplan's
 * target list.  Similarly, INDEX_VAR is used to identify Vars that reference
 * an index column rather than a heap column.  (In PGForeignScan and PGCustomScan
 * plan nodes, INDEX_VAR is abused to signify references to columns of a
 * custom scan tuple type.)  In all these cases, varnoold/varoattno hold the
 * original values.  The code doesn't really need varnoold/varoattno, but they
 * are very useful for debugging and interpreting completed plans, so we keep
 * them around.
 */
#define INNER_VAR 65000 /* reference to inner subplan */
#define OUTER_VAR 65001 /* reference to outer subplan */
#define INDEX_VAR 65002 /* reference to index column */

#define IS_SPECIAL_VARNO(varno) ((varno) >= INNER_VAR)

/* Symbols for the indexes of the special RTE entries in rules */
#define PRS2_OLD_VARNO 1
#define PRS2_NEW_VARNO 2

typedef struct PGVar {
	PGExpr xpr;
	PGIndex varno;          /* index of this var's relation in the range
								 * table, or INNER_VAR/OUTER_VAR/INDEX_VAR */
	PGAttrNumber varattno;  /* attribute number of this var, or zero for
								 * all */
	PGOid vartype;          /* pg_type OID for the type of this var */
	int32_t vartypmod;      /* pg_attribute typmod value */
	PGOid varcollid;        /* OID of collation, or InvalidOid if none */
	PGIndex varlevelsup;    /* for subquery variables referencing outer
								 * relations; 0 in a normal var, >0 means N
								 * levels up */
	PGIndex varnoold;       /* original value of varno, for debugging */
	PGAttrNumber varoattno; /* original value of varattno */
	int location;           /* token location, or -1 if unknown */
} PGVar;

/*
 * PGConst
 *
 * Note: for pg_varlena data types, we make a rule that a PGConst node's value
 * must be in non-extended form (4-byte header, no compression or external
 * references).  This ensures that the PGConst node is self-contained and makes
 * it more likely that equal() will see logically identical values as equal.
 */
typedef struct PGConst {
	PGExpr xpr;
	PGOid consttype;     /* pg_type OID of the constant's datatype */
	int32_t consttypmod; /* typmod value, if any */
	PGOid constcollid;   /* OID of collation, or InvalidOid if none */
	int constlen;        /* typlen of the constant's datatype */
	PGDatum constvalue;  /* the constant's value */
	bool constisnull;    /* whether the constant is null (if true,
								 * constvalue is undefined) */
	bool constbyval;     /* whether this datatype is passed by value.
								 * If true, then all the information is stored
								 * in the Datum. If false, then the PGDatum
								 * contains a pointer to the information. */
	int location;        /* token location, or -1 if unknown */
} PGConst;

/*
 * PGParam
 *
 *		paramkind specifies the kind of parameter. The possible values
 *		for this field are:
 *
 *		PG_PARAM_EXTERN:  The parameter value is supplied from outside the plan.
 *				Such parameters are numbered from 1 to n.
 *
 *		PG_PARAM_EXEC:  The parameter is an internal executor parameter, used
 *				for passing values into and out of sub-queries or from
 *				nestloop joins to their inner scans.
 *				For historical reasons, such parameters are numbered from 0.
 *				These numbers are independent of PG_PARAM_EXTERN numbers.
 *
 *		PG_PARAM_SUBLINK:	The parameter represents an output column of a PGSubLink
 *				node's sub-select.  The column number is contained in the
 *				`paramid' field.  (This type of PGParam is converted to
 *				PG_PARAM_EXEC during planning.)
 *
 *		PG_PARAM_MULTIEXPR:  Like PG_PARAM_SUBLINK, the parameter represents an
 *				output column of a PGSubLink node's sub-select, but here, the
 *				PGSubLink is always a MULTIEXPR SubLink.  The high-order 16 bits
 *				of the `paramid' field contain the SubLink's subLinkId, and
 *				the low-order 16 bits contain the column number.  (This type
 *				of PGParam is also converted to PG_PARAM_EXEC during planning.)
 */
typedef enum PGParamKind { PG_PARAM_EXTERN, PG_PARAM_EXEC, PG_PARAM_SUBLINK, PG_PARAM_MULTIEXPR } PGParamKind;

typedef struct PGParam {
	PGExpr xpr;
	PGParamKind paramkind; /* kind of parameter. See above */
	int paramid;           /* numeric ID for parameter */
	PGOid paramtype;       /* pg_type OID of parameter's datatype */
	int32_t paramtypmod;   /* typmod value, if known */
	PGOid paramcollid;     /* OID of collation, or InvalidOid if none */
	int location;          /* token location, or -1 if unknown */
} PGParam;

/*
 * PGAggref
 *
 * The aggregate's args list is a targetlist, ie, a list of PGTargetEntry nodes.
 *
 * For a normal (non-ordered-set) aggregate, the non-resjunk TargetEntries
 * represent the aggregate's regular arguments (if any) and resjunk TLEs can
 * be added at the end to represent ORDER BY expressions that are not also
 * arguments.  As in a top-level PGQuery, the TLEs can be marked with
 * ressortgroupref indexes to let them be referenced by PGSortGroupClause
 * entries in the aggorder and/or aggdistinct lists.  This represents ORDER BY
 * and DISTINCT operations to be applied to the aggregate input rows before
 * they are passed to the transition function.  The grammar only allows a
 * simple "DISTINCT" specifier for the arguments, but we use the full
 * query-level representation to allow more code sharing.
 *
 * For an ordered-set aggregate, the args list represents the WITHIN GROUP
 * (aggregated) arguments, all of which will be listed in the aggorder list.
 * DISTINCT is not supported in this case, so aggdistinct will be NIL.
 * The direct arguments appear in aggdirectargs (as a list of plain
 * expressions, not PGTargetEntry nodes).
 *
 * aggtranstype is the data type of the state transition values for this
 * aggregate (resolved to an actual type, if agg's transtype is polymorphic).
 * This is determined during planning and is InvalidOid before that.
 *
 * aggargtypes is an OID list of the data types of the direct and regular
 * arguments.  Normally it's redundant with the aggdirectargs and args lists,
 * but in a combining aggregate, it's not because the args list has been
 * replaced with a single argument representing the partial-aggregate
 * transition values.
 *
 * aggsplit indicates the expected partial-aggregation mode for the Aggref's
 * parent plan node.  It's always set to PG_AGGSPLIT_SIMPLE in the parser, but
 * the planner might change it to something else.  We use this mainly as
 * a crosscheck that the Aggrefs match the plan; but note that when aggsplit
 * indicates a non-final mode, aggtype reflects the transition data type
 * not the SQL-level output type of the aggregate.
 */
typedef struct PGAggref {
	PGExpr xpr;
	PGOid aggfnoid;        /* pg_proc PGOid of the aggregate */
	PGOid aggtype;         /* type PGOid of result of the aggregate */
	PGOid aggcollid;       /* OID of collation of result */
	PGOid inputcollid;     /* OID of collation that function should use */
	PGOid aggtranstype;    /* type PGOid of aggregate's transition value */
	PGList *aggargtypes;   /* type Oids of direct and aggregated args */
	PGList *aggdirectargs; /* direct arguments, if an ordered-set agg */
	PGList *args;          /* aggregated arguments and sort expressions */
	PGList *aggorder;      /* ORDER BY (list of PGSortGroupClause) */
	PGList *aggdistinct;   /* DISTINCT (list of PGSortGroupClause) */
	PGExpr *aggfilter;     /* FILTER expression, if any */
	bool aggstar;          /* true if argument list was really '*' */
	bool aggvariadic;      /* true if variadic arguments have been
								 * combined into an array last argument */
	char aggkind;          /* aggregate kind (see pg_aggregate.h) */
	PGIndex agglevelsup;   /* > 0 if agg belongs to outer query */
	PGAggSplit aggsplit;   /* expected agg-splitting mode of parent PGAgg */
	int location;          /* token location, or -1 if unknown */
} PGAggref;

/*
 * PGGroupingFunc
 *
 * A PGGroupingFunc is a GROUPING(...) expression, which behaves in many ways
 * like an aggregate function (e.g. it "belongs" to a specific query level,
 * which might not be the one immediately containing it), but also differs in
 * an important respect: it never evaluates its arguments, they merely
 * designate expressions from the GROUP BY clause of the query level to which
 * it belongs.
 *
 * The spec defines the evaluation of GROUPING() purely by syntactic
 * replacement, but we make it a real expression for optimization purposes so
 * that one PGAgg node can handle multiple grouping sets at once.  Evaluating the
 * result only needs the column positions to check against the grouping set
 * being projected.  However, for EXPLAIN to produce meaningful output, we have
 * to keep the original expressions around, since expression deparse does not
 * give us any feasible way to get at the GROUP BY clause.
 *
 * Also, we treat two PGGroupingFunc nodes as equal if they have equal arguments
 * lists and agglevelsup, without comparing the refs and cols annotations.
 *
 * In raw parse output we have only the args list; parse analysis fills in the
 * refs list, and the planner fills in the cols list.
 */
typedef struct PGGroupingFunc {
	PGExpr xpr;
	PGList *args;        /* arguments, not evaluated but kept for
								 * benefit of EXPLAIN etc. */
	PGList *refs;        /* ressortgrouprefs of arguments */
	PGList *cols;        /* actual column positions set by planner */
	PGIndex agglevelsup; /* same as Aggref.agglevelsup */
	int location;        /* token location */
} PGGroupingFunc;

/*
 * PGWindowFunc
 */
typedef struct PGWindowFunc {
	PGExpr xpr;
	PGOid winfnoid;    /* pg_proc PGOid of the function */
	PGOid wintype;     /* type PGOid of result of the window function */
	PGOid wincollid;   /* OID of collation of result */
	PGOid inputcollid; /* OID of collation that function should use */
	PGList *args;      /* arguments to the window function */
	PGExpr *aggfilter; /* FILTER expression, if any */
	PGIndex winref;    /* index of associated PGWindowClause */
	bool winstar;      /* true if argument list was really '*' */
	bool winagg;       /* is function a simple aggregate? */
	int location;      /* token location, or -1 if unknown */
} PGWindowFunc;

/* ----------------
 *	PGArrayRef: describes an array subscripting operation
 *
 * An PGArrayRef can describe fetching a single element from an array,
 * fetching a subarray (array slice), storing a single element into
 * an array, or storing a slice.  The "store" cases work with an
 * initial array value and a source value that is inserted into the
 * appropriate part of the array; the result of the operation is an
 * entire new modified array value.
 *
 * If reflowerindexpr = NIL, then we are fetching or storing a single array
 * element at the subscripts given by refupperindexpr.  Otherwise we are
 * fetching or storing an array slice, that is a rectangular subarray
 * with lower and upper bounds given by the index expressions.
 * reflowerindexpr must be the same length as refupperindexpr when it
 * is not NIL.
 *
 * In the slice case, individual expressions in the subscript lists can be
 * NULL, meaning "substitute the array's current lower or upper bound".
 *
 * Note: the result datatype is the element type when fetching a single
 * element; but it is the array type when doing subarray fetch or either
 * type of store.
 *
 * Note: for the cases where an array is returned, if refexpr yields a R/W
 * expanded array, then the implementation is allowed to modify that object
 * in-place and return the same object.)
 * ----------------
 */
typedef struct PGArrayRef {
	PGExpr xpr;
	PGOid refarraytype;      /* type of the array proper */
	PGOid refelemtype;       /* type of the array elements */
	int32_t reftypmod;       /* typmod of the array (and elements too) */
	PGOid refcollid;         /* OID of collation, or InvalidOid if none */
	PGList *refupperindexpr; /* expressions that evaluate to upper
									 * array indexes */
	PGList *reflowerindexpr; /* expressions that evaluate to lower
									 * array indexes, or NIL for single array
									 * element */
	PGExpr *refexpr;         /* the expression that evaluates to an array
								 * value */
	PGExpr *refassgnexpr;    /* expression for the source value, or NULL if
								 * fetch */
} PGArrayRef;

/*
 * PGCoercionContext - distinguishes the allowed set of type casts
 *
 * NB: ordering of the alternatives is significant; later (larger) values
 * allow more casts than earlier ones.
 */
typedef enum PGCoercionContext {
	PG_COERCION_IMPLICIT,   /* coercion in context of expression */
	PG_COERCION_ASSIGNMENT, /* coercion in context of assignment */
	PG_COERCION_EXPLICIT    /* explicit cast operation */
} PGCoercionContext;

/*
 * PGCoercionForm - how to display a node that could have come from a cast
 *
 * NB: equal() ignores PGCoercionForm fields, therefore this *must* not carry
 * any semantically significant information.  We need that behavior so that
 * the planner will consider equivalent implicit and explicit casts to be
 * equivalent.  In cases where those actually behave differently, the coercion
 * function's arguments will be different.
 */
typedef enum PGCoercionForm {
	PG_COERCE_EXPLICIT_CALL, /* display as a function call */
	PG_COERCE_EXPLICIT_CAST, /* display as an explicit cast */
	PG_COERCE_IMPLICIT_CAST  /* implicit cast, so hide it */
} PGCoercionForm;

/*
 * PGFuncExpr - expression node for a function call
 */
typedef struct PGFuncExpr {
	PGExpr xpr;
	PGOid funcid;              /* PG_PROC OID of the function */
	PGOid funcresulttype;      /* PG_TYPE OID of result value */
	bool funcretset;           /* true if function returns set */
	bool funcvariadic;         /* true if variadic arguments have been
								 * combined into an array last argument */
	PGCoercionForm funcformat; /* how to display this function call */
	PGOid funccollid;          /* OID of collation of result */
	PGOid inputcollid;         /* OID of collation that function should use */
	PGList *args;              /* arguments to the function */
	int location;              /* token location, or -1 if unknown */
} PGFuncExpr;

/*
 * PGNamedArgExpr - a named argument of a function
 *
 * This node type can only appear in the args list of a PGFuncCall or PGFuncExpr
 * node.  We support pure positional call notation (no named arguments),
 * named notation (all arguments are named), and mixed notation (unnamed
 * arguments followed by named ones).
 *
 * Parse analysis sets argnumber to the positional index of the argument,
 * but doesn't rearrange the argument list.
 *
 * The planner will convert argument lists to pure positional notation
 * during expression preprocessing, so execution never sees a NamedArgExpr.
 */
typedef struct PGNamedArgExpr {
	PGExpr xpr;
	PGExpr *arg;   /* the argument expression */
	char *name;    /* the name */
	int argnumber; /* argument's number in positional notation */
	int location;  /* argument name location, or -1 if unknown */
} PGNamedArgExpr;

/*
 * PGOpExpr - expression node for an operator invocation
 *
 * Semantically, this is essentially the same as a function call.
 *
 * Note that opfuncid is not necessarily filled in immediately on creation
 * of the node.  The planner makes sure it is valid before passing the node
 * tree to the executor, but during parsing/planning opfuncid can be 0.
 */
typedef struct PGOpExpr {
	PGExpr xpr;
	PGOid opno;         /* PG_OPERATOR OID of the operator */
	PGOid opfuncid;     /* PG_PROC OID of underlying function */
	PGOid opresulttype; /* PG_TYPE OID of result value */
	bool opretset;      /* true if operator returns set */
	PGOid opcollid;     /* OID of collation of result */
	PGOid inputcollid;  /* OID of collation that operator should use */
	PGList *args;       /* arguments to the operator (1 or 2) */
	int location;       /* token location, or -1 if unknown */
} PGOpExpr;

/*
 * DistinctExpr - expression node for "x IS DISTINCT FROM y"
 *
 * Except for the nodetag, this is represented identically to an PGOpExpr
 * referencing the "=" operator for x and y.
 * We use "=", not the more obvious "<>", because more datatypes have "="
 * than "<>".  This means the executor must invert the operator result.
 * Note that the operator function won't be called at all if either input
 * is NULL, since then the result can be determined directly.
 */
typedef PGOpExpr DistinctExpr;

/*
 * NullIfExpr - a NULLIF expression
 *
 * Like DistinctExpr, this is represented the same as an PGOpExpr referencing
 * the "=" operator for x and y.
 */
typedef PGOpExpr NullIfExpr;

/*
 * PGScalarArrayOpExpr - expression node for "scalar op ANY/ALL (array)"
 *
 * The operator must yield boolean.  It is applied to the left operand
 * and each element of the righthand array, and the results are combined
 * with OR or AND (for ANY or ALL respectively).  The node representation
 * is almost the same as for the underlying operator, but we need a useOr
 * flag to remember whether it's ANY or ALL, and we don't have to store
 * the result type (or the collation) because it must be boolean.
 */
typedef struct PGScalarArrayOpExpr {
	PGExpr xpr;
	PGOid opno;        /* PG_OPERATOR OID of the operator */
	PGOid opfuncid;    /* PG_PROC OID of underlying function */
	bool useOr;        /* true for ANY, false for ALL */
	PGOid inputcollid; /* OID of collation that operator should use */
	PGList *args;      /* the scalar and array operands */
	int location;      /* token location, or -1 if unknown */
} PGScalarArrayOpExpr;

/*
 * PGBoolExpr - expression node for the basic Boolean operators AND, OR, NOT
 *
 * Notice the arguments are given as a List.  For NOT, of course the list
 * must always have exactly one element.  For AND and OR, there can be two
 * or more arguments.
 */
typedef enum PGBoolExprType { PG_AND_EXPR, PG_OR_EXPR, PG_NOT_EXPR } PGBoolExprType;

typedef struct PGBoolExpr {
	PGExpr xpr;
	PGBoolExprType boolop;
	PGList *args; /* arguments to this expression */
	int location; /* token location, or -1 if unknown */
} PGBoolExpr;

/*
 * PGSubLink
 *
 * A PGSubLink represents a subselect appearing in an expression, and in some
 * cases also the combining operator(s) just above it.  The subLinkType
 * indicates the form of the expression represented:
 *	PG_EXISTS_SUBLINK		EXISTS(SELECT ...)
 *	PG_ALL_SUBLINK			(lefthand) op ALL (SELECT ...)
 *	PG_ANY_SUBLINK			(lefthand) op ANY (SELECT ...)
 *	PG_ROWCOMPARE_SUBLINK	(lefthand) op (SELECT ...)
 *	PG_EXPR_SUBLINK		(SELECT with single targetlist item ...)
 *	PG_MULTIEXPR_SUBLINK	(SELECT with multiple targetlist items ...)
 *	PG_ARRAY_SUBLINK		ARRAY(SELECT with single targetlist item ...)
 *	PG_CTE_SUBLINK			WITH query (never actually part of an expression)
 * For ALL, ANY, and ROWCOMPARE, the lefthand is a list of expressions of the
 * same length as the subselect's targetlist.  ROWCOMPARE will *always* have
 * a list with more than one entry; if the subselect has just one target
 * then the parser will create an PG_EXPR_SUBLINK instead (and any operator
 * above the subselect will be represented separately).
 * ROWCOMPARE, EXPR, and MULTIEXPR require the subselect to deliver at most
 * one row (if it returns no rows, the result is NULL).
 * ALL, ANY, and ROWCOMPARE require the combining operators to deliver boolean
 * results.  ALL and ANY combine the per-row results using AND and OR
 * semantics respectively.
 * ARRAY requires just one target column, and creates an array of the target
 * column's type using any number of rows resulting from the subselect.
 *
 * PGSubLink is classed as an PGExpr node, but it is not actually executable;
 * it must be replaced in the expression tree by a PGSubPlan node during
 * planning.
 *
 * NOTE: in the raw output of gram.y, testexpr contains just the raw form
 * of the lefthand expression (if any), and operName is the String name of
 * the combining operator.  Also, subselect is a raw parsetree.  During parse
 * analysis, the parser transforms testexpr into a complete boolean expression
 * that compares the lefthand value(s) to PG_PARAM_SUBLINK nodes representing the
 * output columns of the subselect.  And subselect is transformed to a Query.
 * This is the representation seen in saved rules and in the rewriter.
 *
 * In EXISTS, EXPR, MULTIEXPR, and ARRAY SubLinks, testexpr and operName
 * are unused and are always null.
 *
 * subLinkId is currently used only for MULTIEXPR SubLinks, and is zero in
 * other SubLinks.  This number identifies different multiple-assignment
 * subqueries within an UPDATE statement's SET list.  It is unique only
 * within a particular targetlist.  The output column(s) of the MULTIEXPR
 * are referenced by PG_PARAM_MULTIEXPR Params appearing elsewhere in the tlist.
 *
 * The PG_CTE_SUBLINK case never occurs in actual PGSubLink nodes, but it is used
 * in SubPlans generated for WITH subqueries.
 */
typedef enum PGSubLinkType {
	PG_EXISTS_SUBLINK,
	PG_ALL_SUBLINK,
	PG_ANY_SUBLINK,
	PG_ROWCOMPARE_SUBLINK,
	PG_EXPR_SUBLINK,
	PG_MULTIEXPR_SUBLINK,
	PG_ARRAY_SUBLINK,
	PG_CTE_SUBLINK /* for SubPlans only */
} PGSubLinkType;

typedef struct PGSubLink {
	PGExpr xpr;
	PGSubLinkType subLinkType; /* see above */
	int subLinkId;             /* ID (1..n); 0 if not MULTIEXPR */
	PGNode *testexpr;          /* outer-query test for ALL/ANY/ROWCOMPARE */
	PGList *operName;          /* originally specified operator name */
	PGNode *subselect;         /* subselect as PGQuery* or raw parsetree */
	int location;              /* token location, or -1 if unknown */
} PGSubLink;

/*
 * PGSubPlan - executable expression node for a subplan (sub-SELECT)
 *
 * The planner replaces PGSubLink nodes in expression trees with PGSubPlan
 * nodes after it has finished planning the subquery.  PGSubPlan references
 * a sub-plantree stored in the subplans list of the toplevel PlannedStmt.
 * (We avoid a direct link to make it easier to copy expression trees
 * without causing multiple processing of the subplan.)
 *
 * In an ordinary subplan, testexpr points to an executable expression
 * (PGOpExpr, an AND/OR tree of OpExprs, or PGRowCompareExpr) for the combining
 * operator(s); the left-hand arguments are the original lefthand expressions,
 * and the right-hand arguments are PG_PARAM_EXEC PGParam nodes representing the
 * outputs of the sub-select.  (NOTE: runtime coercion functions may be
 * inserted as well.)  This is just the same expression tree as testexpr in
 * the original PGSubLink node, but the PG_PARAM_SUBLINK nodes are replaced by
 * suitably numbered PG_PARAM_EXEC nodes.
 *
 * If the sub-select becomes an initplan rather than a subplan, the executable
 * expression is part of the outer plan's expression tree (and the PGSubPlan
 * node itself is not, but rather is found in the outer plan's initPlan
 * list).  In this case testexpr is NULL to avoid duplication.
 *
 * The planner also derives lists of the values that need to be passed into
 * and out of the subplan.  Input values are represented as a list "args" of
 * expressions to be evaluated in the outer-query context (currently these
 * args are always just Vars, but in principle they could be any expression).
 * The values are assigned to the global PG_PARAM_EXEC params indexed by parParam
 * (the parParam and args lists must have the same ordering).  setParam is a
 * list of the PG_PARAM_EXEC params that are computed by the sub-select, if it
 * is an initplan; they are listed in order by sub-select output column
 * position.  (parParam and setParam are integer Lists, not Bitmapsets,
 * because their ordering is significant.)
 *
 * Also, the planner computes startup and per-call costs for use of the
 * SubPlan.  Note that these include the cost of the subquery proper,
 * evaluation of the testexpr if any, and any hashtable management overhead.
 */
typedef struct PGSubPlan {
	PGExpr xpr;
	/* Fields copied from original PGSubLink: */
	PGSubLinkType subLinkType; /* see above */
	/* The combining operators, transformed to an executable expression: */
	PGNode *testexpr; /* PGOpExpr or PGRowCompareExpr expression tree */
	PGList *paramIds; /* IDs of Params embedded in the above */
	/* Identification of the PGPlan tree to use: */
	int plan_id; /* PGIndex (from 1) in PlannedStmt.subplans */
	/* Identification of the PGSubPlan for EXPLAIN and debugging purposes: */
	char *plan_name; /* A name assigned during planning */
	/* Extra data useful for determining subplan's output type: */
	PGOid firstColType;      /* Type of first column of subplan result */
	int32_t firstColTypmod;  /* Typmod of first column of subplan result */
	PGOid firstColCollation; /* Collation of first column of subplan
									 * result */
	/* Information about execution strategy: */
	bool useHashTable;   /* true to store subselect output in a hash
								 * table (implies we are doing "IN") */
	bool unknownEqFalse; /* true if it's okay to return false when the
								 * spec result is UNKNOWN; this allows much
								 * simpler handling of null values */
	bool parallel_safe;  /* is the subplan parallel-safe? */
	/* Note: parallel_safe does not consider contents of testexpr or args */
	/* Information for passing params into and out of the subselect: */
	/* setParam and parParam are lists of integers (param IDs) */
	PGList *setParam; /* initplan subqueries have to set these
								 * Params for parent plan */
	PGList *parParam; /* indices of input Params from parent plan */
	PGList *args;     /* exprs to pass as parParam values */
	/* Estimated execution costs: */
	Cost startup_cost;  /* one-time setup cost */
	Cost per_call_cost; /* cost for each subplan evaluation */
} PGSubPlan;

/*
 * PGAlternativeSubPlan - expression node for a choice among SubPlans
 *
 * The subplans are given as a PGList so that the node definition need not
 * change if there's ever more than two alternatives.  For the moment,
 * though, there are always exactly two; and the first one is the fast-start
 * plan.
 */
typedef struct PGAlternativeSubPlan {
	PGExpr xpr;
	PGList *subplans; /* SubPlan(s) with equivalent results */
} PGAlternativeSubPlan;

/* ----------------
 * PGFieldSelect
 *
 * PGFieldSelect represents the operation of extracting one field from a tuple
 * value.  At runtime, the input expression is expected to yield a rowtype
 * Datum.  The specified field number is extracted and returned as a Datum.
 * ----------------
 */

typedef struct PGFieldSelect {
	PGExpr xpr;
	PGExpr *arg;           /* input expression */
	PGAttrNumber fieldnum; /* attribute number of field to extract */
	PGOid resulttype;      /* type of the field (result type of this
								 * node) */
	int32_t resulttypmod;  /* output typmod (usually -1) */
	PGOid resultcollid;    /* OID of collation of the field */
} PGFieldSelect;

/* ----------------
 * PGFieldStore
 *
 * PGFieldStore represents the operation of modifying one field in a tuple
 * value, yielding a new tuple value (the input is not touched!).  Like
 * the assign case of PGArrayRef, this is used to implement UPDATE of a
 * portion of a column.
 *
 * A single PGFieldStore can actually represent updates of several different
 * fields.  The parser only generates FieldStores with single-element lists,
 * but the planner will collapse multiple updates of the same base column
 * into one FieldStore.
 * ----------------
 */

typedef struct PGFieldStore {
	PGExpr xpr;
	PGExpr *arg;       /* input tuple value */
	PGList *newvals;   /* new value(s) for field(s) */
	PGList *fieldnums; /* integer list of field attnums */
	PGOid resulttype;  /* type of result (same as type of arg) */
	                   /* Like PGRowExpr, we deliberately omit a typmod and collation here */
} PGFieldStore;

/* ----------------
 * PGRelabelType
 *
 * PGRelabelType represents a "dummy" type coercion between two binary-
 * compatible datatypes, such as reinterpreting the result of an OID
 * expression as an int4.  It is a no-op at runtime; we only need it
 * to provide a place to store the correct type to be attributed to
 * the expression result during type resolution.  (We can't get away
 * with just overwriting the type field of the input expression node,
 * so we need a separate node to show the coercion's result type.)
 * ----------------
 */

typedef struct PGRelabelType {
	PGExpr xpr;
	PGExpr *arg;                  /* input expression */
	PGOid resulttype;             /* output type of coercion expression */
	int32_t resulttypmod;         /* output typmod (usually -1) */
	PGOid resultcollid;           /* OID of collation, or InvalidOid if none */
	PGCoercionForm relabelformat; /* how to display this node */
	int location;                 /* token location, or -1 if unknown */
} PGRelabelType;

/* ----------------
 * PGCoerceViaIO
 *
 * PGCoerceViaIO represents a type coercion between two types whose textual
 * representations are compatible, implemented by invoking the source type's
 * typoutput function then the destination type's typinput function.
 * ----------------
 */

typedef struct PGCoerceViaIO {
	PGExpr xpr;
	PGExpr *arg;      /* input expression */
	PGOid resulttype; /* output type of coercion */
	/* output typmod is not stored, but is presumed -1 */
	PGOid resultcollid;          /* OID of collation, or InvalidOid if none */
	PGCoercionForm coerceformat; /* how to display this node */
	int location;                /* token location, or -1 if unknown */
} PGCoerceViaIO;

/* ----------------
 * PGArrayCoerceExpr
 *
 * PGArrayCoerceExpr represents a type coercion from one array type to another,
 * which is implemented by applying the indicated element-type coercion
 * function to each element of the source array.  If elemfuncid is InvalidOid
 * then the element types are binary-compatible, but the coercion still
 * requires some effort (we have to fix the element type ID stored in the
 * array header).
 * ----------------
 */

typedef struct PGArrayCoerceExpr {
	PGExpr xpr;
	PGExpr *arg;                 /* input expression (yields an array) */
	PGOid elemfuncid;            /* OID of element coercion function, or 0 */
	PGOid resulttype;            /* output type of coercion (an array type) */
	int32_t resulttypmod;        /* output typmod (also element typmod) */
	PGOid resultcollid;          /* OID of collation, or InvalidOid if none */
	bool isExplicit;             /* conversion semantics flag to pass to func */
	PGCoercionForm coerceformat; /* how to display this node */
	int location;                /* token location, or -1 if unknown */
} PGArrayCoerceExpr;

/* ----------------
 * PGConvertRowtypeExpr
 *
 * PGConvertRowtypeExpr represents a type coercion from one composite type
 * to another, where the source type is guaranteed to contain all the columns
 * needed for the destination type plus possibly others; the columns need not
 * be in the same positions, but are matched up by name.  This is primarily
 * used to convert a whole-row value of an inheritance child table into a
 * valid whole-row value of its parent table's rowtype.
 * ----------------
 */

typedef struct PGConvertRowtypeExpr {
	PGExpr xpr;
	PGExpr *arg;      /* input expression */
	PGOid resulttype; /* output type (always a composite type) */
	/* Like PGRowExpr, we deliberately omit a typmod and collation here */
	PGCoercionForm convertformat; /* how to display this node */
	int location;                 /* token location, or -1 if unknown */
} PGConvertRowtypeExpr;

/*----------
 * PGCollateExpr - COLLATE
 *
 * The planner replaces PGCollateExpr with PGRelabelType during expression
 * preprocessing, so execution never sees a CollateExpr.
 *----------
 */
typedef struct PGCollateExpr {
	PGExpr xpr;
	PGExpr *arg;   /* input expression */
	PGOid collOid; /* collation's OID */
	int location;  /* token location, or -1 if unknown */
} PGCollateExpr;

/*----------
 * PGCaseExpr - a CASE expression
 *
 * We support two distinct forms of CASE expression:
 *		CASE WHEN boolexpr THEN expr [ WHEN boolexpr THEN expr ... ]
 *		CASE testexpr WHEN compexpr THEN expr [ WHEN compexpr THEN expr ... ]
 * These are distinguishable by the "arg" field being NULL in the first case
 * and the testexpr in the second case.
 *
 * In the raw grammar output for the second form, the condition expressions
 * of the WHEN clauses are just the comparison values.  Parse analysis
 * converts these to valid boolean expressions of the form
 *		PGCaseTestExpr '=' compexpr
 * where the PGCaseTestExpr node is a placeholder that emits the correct
 * value at runtime.  This structure is used so that the testexpr need be
 * evaluated only once.  Note that after parse analysis, the condition
 * expressions always yield boolean.
 *
 * Note: we can test whether a PGCaseExpr has been through parse analysis
 * yet by checking whether casetype is InvalidOid or not.
 *----------
 */
typedef struct PGCaseExpr {
	PGExpr xpr;
	PGOid casetype;    /* type of expression result */
	PGOid casecollid;  /* OID of collation, or InvalidOid if none */
	PGExpr *arg;       /* implicit equality comparison argument */
	PGList *args;      /* the arguments (list of WHEN clauses) */
	PGExpr *defresult; /* the default result (ELSE clause) */
	int location;      /* token location, or -1 if unknown */
} PGCaseExpr;

/*
 * PGCaseWhen - one arm of a CASE expression
 */
typedef struct PGCaseWhen {
	PGExpr xpr;
	PGExpr *expr;   /* condition expression */
	PGExpr *result; /* substitution result */
	int location;   /* token location, or -1 if unknown */
} PGCaseWhen;

/*
 * Placeholder node for the test value to be processed by a CASE expression.
 * This is effectively like a PGParam, but can be implemented more simply
 * since we need only one replacement value at a time.
 *
 * We also use this in nested UPDATE expressions.
 * See transformAssignmentIndirection().
 */
typedef struct PGCaseTestExpr {
	PGExpr xpr;
	PGOid typeId;    /* type for substituted value */
	int32_t typeMod; /* typemod for substituted value */
	PGOid collation; /* collation for the substituted value */
} PGCaseTestExpr;

/*
 * PGArrayExpr - an ARRAY[] expression
 *
 * Note: if multidims is false, the constituent expressions all yield the
 * scalar type identified by element_typeid.  If multidims is true, the
 * constituent expressions all yield arrays of element_typeid (ie, the same
 * type as array_typeid); at runtime we must check for compatible subscripts.
 */
typedef struct PGArrayExpr {
	PGExpr xpr;
	PGOid array_typeid;   /* type of expression result */
	PGOid array_collid;   /* OID of collation, or InvalidOid if none */
	PGOid element_typeid; /* common type of array elements */
	PGList *elements;     /* the array elements or sub-arrays */
	bool multidims;       /* true if elements are sub-arrays */
	int location;         /* token location, or -1 if unknown */
} PGArrayExpr;

/*
 * PGRowExpr - a ROW() expression
 *
 * Note: the list of fields must have a one-for-one correspondence with
 * physical fields of the associated rowtype, although it is okay for it
 * to be shorter than the rowtype.  That is, the N'th list element must
 * match up with the N'th physical field.  When the N'th physical field
 * is a dropped column (attisdropped) then the N'th list element can just
 * be a NULL constant.  (This case can only occur for named composite types,
 * not RECORD types, since those are built from the PGRowExpr itself rather
 * than vice versa.)  It is important not to assume that length(args) is
 * the same as the number of columns logically present in the rowtype.
 *
 * colnames provides field names in cases where the names can't easily be
 * obtained otherwise.  Names *must* be provided if row_typeid is RECORDOID.
 * If row_typeid identifies a known composite type, colnames can be NIL to
 * indicate the type's cataloged field names apply.  Note that colnames can
 * be non-NIL even for a composite type, and typically is when the PGRowExpr
 * was created by expanding a whole-row Var.  This is so that we can retain
 * the column alias names of the RTE that the PGVar referenced (which would
 * otherwise be very difficult to extract from the parsetree).  Like the
 * args list, colnames is one-for-one with physical fields of the rowtype.
 */
typedef struct PGRowExpr {
	PGExpr xpr;
	PGList *args;     /* the fields */
	PGOid row_typeid; /* RECORDOID or a composite type's ID */

	/*
	 * Note: we deliberately do NOT store a typmod.  Although a typmod will be
	 * associated with specific RECORD types at runtime, it will differ for
	 * different backends, and so cannot safely be stored in stored
	 * parsetrees.  We must assume typmod -1 for a PGRowExpr node.
	 *
	 * We don't need to store a collation either.  The result type is
	 * necessarily composite, and composite types never have a collation.
	 */
	PGCoercionForm row_format; /* how to display this node */
	PGList *colnames;          /* list of String, or NIL */
	int location;              /* token location, or -1 if unknown */
} PGRowExpr;

/*
 * PGRowCompareExpr - row-wise comparison, such as (a, b) <= (1, 2)
 *
 * We support row comparison for any operator that can be determined to
 * act like =, <>, <, <=, >, or >= (we determine this by looking for the
 * operator in btree opfamilies).  Note that the same operator name might
 * map to a different operator for each pair of row elements, since the
 * element datatypes can vary.
 *
 * A PGRowCompareExpr node is only generated for the < <= > >= cases;
 * the = and <> cases are translated to simple AND or OR combinations
 * of the pairwise comparisons.  However, we include = and <> in the
 * PGRowCompareType enum for the convenience of parser logic.
 */
typedef enum PGRowCompareType {
	/* Values of this enum are chosen to match btree strategy numbers */
	PG_ROWCOMPARE_LT = 1, /* BTLessStrategyNumber */
	PG_ROWCOMPARE_LE = 2, /* BTLessEqualStrategyNumber */
	PG_ROWCOMPARE_EQ = 3, /* BTEqualStrategyNumber */
	PG_ROWCOMPARE_GE = 4, /* BTGreaterEqualStrategyNumber */
	PG_ROWCOMPARE_GT = 5, /* BTGreaterStrategyNumber */
	PG_ROWCOMPARE_NE = 6  /* no such btree strategy */
} PGRowCompareType;

typedef struct PGRowCompareExpr {
	PGExpr xpr;
	PGRowCompareType rctype; /* LT LE GE or GT, never EQ or NE */
	PGList *opnos;           /* OID list of pairwise comparison ops */
	PGList *opfamilies;      /* OID list of containing operator families */
	PGList *inputcollids;    /* OID list of collations for comparisons */
	PGList *largs;           /* the left-hand input arguments */
	PGList *rargs;           /* the right-hand input arguments */
} PGRowCompareExpr;

/*
 * PGCoalesceExpr - a COALESCE expression
 */
typedef struct PGCoalesceExpr {
	PGExpr xpr;
	PGOid coalescetype;   /* type of expression result */
	PGOid coalescecollid; /* OID of collation, or InvalidOid if none */
	PGList *args;         /* the arguments */
	int location;         /* token location, or -1 if unknown */
} PGCoalesceExpr;

/*
 * PGMinMaxExpr - a GREATEST or LEAST function
 */
typedef enum PGMinMaxOp { PG_IS_GREATEST, IS_LEAST } PGMinMaxOp;

typedef struct PGMinMaxExpr {
	PGExpr xpr;
	PGOid minmaxtype;   /* common type of arguments and result */
	PGOid minmaxcollid; /* OID of collation of result */
	PGOid inputcollid;  /* OID of collation that function should use */
	PGMinMaxOp op;      /* function to execute */
	PGList *args;       /* the arguments */
	int location;       /* token location, or -1 if unknown */
} PGMinMaxExpr;

/*
 * PGSQLValueFunction - parameterless functions with special grammar productions
 *
 * The SQL standard categorizes some of these as <datetime value function>
 * and others as <general value specification>.  We call 'em SQLValueFunctions
 * for lack of a better term.  We store type and typmod of the result so that
 * some code doesn't need to know each function individually, and because
 * we would need to store typmod anyway for some of the datetime functions.
 * Note that currently, all variants return non-collating datatypes, so we do
 * not need a collation field; also, all these functions are stable.
 */
typedef enum PGSQLValueFunctionOp {
	PG_SVFOP_CURRENT_DATE,
	PG_SVFOP_CURRENT_TIME,
	PG_SVFOP_CURRENT_TIME_N,
	PG_SVFOP_CURRENT_TIMESTAMP,
	PG_SVFOP_CURRENT_TIMESTAMP_N,
	PG_SVFOP_LOCALTIME,
	PG_SVFOP_LOCALTIME_N,
	PG_SVFOP_LOCALTIMESTAMP,
	PG_SVFOP_LOCALTIMESTAMP_N,
	PG_SVFOP_CURRENT_ROLE,
	PG_SVFOP_CURRENT_USER,
	PG_SVFOP_USER,
	PG_SVFOP_SESSION_USER,
	PG_SVFOP_CURRENT_CATALOG,
	PG_SVFOP_CURRENT_SCHEMA
} PGSQLValueFunctionOp;

typedef struct PGSQLValueFunction {
	PGExpr xpr;
	PGSQLValueFunctionOp op; /* which function this is */
	PGOid type;              /* result type/typmod */
	int32_t typmod;
	int location; /* token location, or -1 if unknown */
} PGSQLValueFunction;

/* ----------------
 * PGNullTest
 *
 * PGNullTest represents the operation of testing a value for NULLness.
 * The appropriate test is performed and returned as a boolean Datum.
 *
 * When argisrow is false, this simply represents a test for the null value.
 *
 * When argisrow is true, the input expression must yield a rowtype, and
 * the node implements "row IS [NOT] NULL" per the SQL standard.  This
 * includes checking individual fields for NULLness when the row datum
 * itself isn't NULL.
 *
 * NOTE: the combination of a rowtype input and argisrow==false does NOT
 * correspond to the SQL notation "row IS [NOT] NULL"; instead, this case
 * represents the SQL notation "row IS [NOT] DISTINCT FROM NULL".
 * ----------------
 */

typedef enum PGNullTestType { PG_IS_NULL, IS_NOT_NULL } PGNullTestType;

typedef struct PGNullTest {
	PGExpr xpr;
	PGExpr *arg;                 /* input expression */
	PGNullTestType nulltesttype; /* IS NULL, IS NOT NULL */
	bool argisrow;               /* T to perform field-by-field null checks */
	int location;                /* token location, or -1 if unknown */
} PGNullTest;

/*
 * PGBooleanTest
 *
 * PGBooleanTest represents the operation of determining whether a boolean
 * is true, false, or UNKNOWN (ie, NULL).  All six meaningful combinations
 * are supported.  Note that a NULL input does *not* cause a NULL result.
 * The appropriate test is performed and returned as a boolean Datum.
 */

typedef enum PGBoolTestType {
	PG_IS_TRUE,
	IS_NOT_TRUE,
	IS_FALSE,
	IS_NOT_FALSE,
	IS_UNKNOWN,
	IS_NOT_UNKNOWN
} PGBoolTestType;

typedef struct PGBooleanTest {
	PGExpr xpr;
	PGExpr *arg;                 /* input expression */
	PGBoolTestType booltesttype; /* test type */
	int location;                /* token location, or -1 if unknown */
} PGBooleanTest;

/*
 * PGCoerceToDomain
 *
 * PGCoerceToDomain represents the operation of coercing a value to a domain
 * type.  At runtime (and not before) the precise set of constraints to be
 * checked will be determined.  If the value passes, it is returned as the
 * result; if not, an error is raised.  Note that this is equivalent to
 * PGRelabelType in the scenario where no constraints are applied.
 */
typedef struct PGCoerceToDomain {
	PGExpr xpr;
	PGExpr *arg;                   /* input expression */
	PGOid resulttype;              /* domain type ID (result type) */
	int32_t resulttypmod;          /* output typmod (currently always -1) */
	PGOid resultcollid;            /* OID of collation, or InvalidOid if none */
	PGCoercionForm coercionformat; /* how to display this node */
	int location;                  /* token location, or -1 if unknown */
} PGCoerceToDomain;

/*
 * Placeholder node for the value to be processed by a domain's check
 * constraint.  This is effectively like a PGParam, but can be implemented more
 * simply since we need only one replacement value at a time.
 *
 * Note: the typeId/typeMod/collation will be set from the domain's base type,
 * not the domain itself.  This is because we shouldn't consider the value
 * to be a member of the domain if we haven't yet checked its constraints.
 */
typedef struct PGCoerceToDomainValue {
	PGExpr xpr;
	PGOid typeId;    /* type for substituted value */
	int32_t typeMod; /* typemod for substituted value */
	PGOid collation; /* collation for the substituted value */
	int location;    /* token location, or -1 if unknown */
} PGCoerceToDomainValue;

/*
 * Placeholder node for a DEFAULT marker in an INSERT or UPDATE command.
 *
 * This is not an executable expression: it must be replaced by the actual
 * column default expression during rewriting.  But it is convenient to
 * treat it as an expression node during parsing and rewriting.
 */
typedef struct PGSetToDefault {
	PGExpr xpr;
	PGOid typeId;    /* type for substituted value */
	int32_t typeMod; /* typemod for substituted value */
	PGOid collation; /* collation for the substituted value */
	int location;    /* token location, or -1 if unknown */
} PGSetToDefault;

/*
 * PGNode representing [WHERE] CURRENT OF cursor_name
 *
 * CURRENT OF is a bit like a PGVar, in that it carries the rangetable index
 * of the target relation being constrained; this aids placing the expression
 * correctly during planning.  We can assume however that its "levelsup" is
 * always zero, due to the syntactic constraints on where it can appear.
 *
 * The referenced cursor can be represented either as a hardwired string
 * or as a reference to a run-time parameter of type REFCURSOR.  The latter
 * case is for the convenience of plpgsql.
 */
typedef struct PGCurrentOfExpr {
	PGExpr xpr;
	PGIndex cvarno;    /* RT index of target relation */
	char *cursor_name; /* name of referenced cursor, or NULL */
	int cursor_param;  /* refcursor parameter number, or 0 */
} PGCurrentOfExpr;

/*
 * PGNextValueExpr - get next value from sequence
 *
 * This has the same effect as calling the nextval() function, but it does not
 * check permissions on the sequence.  This is used for identity columns,
 * where the sequence is an implicit dependency without its own permissions.
 */
typedef struct PGNextValueExpr {
	PGExpr xpr;
	PGOid seqid;
	PGOid typeId;
} PGNextValueExpr;

/*
 * PGInferenceElem - an element of a unique index inference specification
 *
 * This mostly matches the structure of IndexElems, but having a dedicated
 * primnode allows for a clean separation between the use of index parameters
 * by utility commands, and this node.
 */
typedef struct PGInferenceElem {
	PGExpr xpr;
	PGNode *expr;       /* expression to infer from, or NULL */
	PGOid infercollid;  /* OID of collation, or InvalidOid */
	PGOid inferopclass; /* OID of att opclass, or InvalidOid */
} PGInferenceElem;

/*--------------------
 * PGTargetEntry -
 *	   a target entry (used in query target lists)
 *
 * Strictly speaking, a PGTargetEntry isn't an expression node (since it can't
 * be evaluated by ExecEvalExpr).  But we treat it as one anyway, since in
 * very many places it's convenient to process a whole query targetlist as a
 * single expression tree.
 *
 * In a SELECT's targetlist, resno should always be equal to the item's
 * ordinal position (counting from 1).  However, in an INSERT or UPDATE
 * targetlist, resno represents the attribute number of the destination
 * column for the item; so there may be missing or out-of-order resnos.
 * It is even legal to have duplicated resnos; consider
 *		UPDATE table SET arraycol[1] = ..., arraycol[2] = ..., ...
 * The two meanings come together in the executor, because the planner
 * transforms INSERT/UPDATE tlists into a normalized form with exactly
 * one entry for each column of the destination table.  Before that's
 * happened, however, it is risky to assume that resno == position.
 * Generally get_tle_by_resno() should be used rather than list_nth()
 * to fetch tlist entries by resno, and only in SELECT should you assume
 * that resno is a unique identifier.
 *
 * resname is required to represent the correct column name in non-resjunk
 * entries of top-level SELECT targetlists, since it will be used as the
 * column title sent to the frontend.  In most other contexts it is only
 * a debugging aid, and may be wrong or even NULL.  (In particular, it may
 * be wrong in a tlist from a stored rule, if the referenced column has been
 * renamed by ALTER TABLE since the rule was made.  Also, the planner tends
 * to store NULL rather than look up a valid name for tlist entries in
 * non-toplevel plan nodes.)  In resjunk entries, resname should be either
 * a specific system-generated name (such as "ctid") or NULL; anything else
 * risks confusing ExecGetJunkAttribute!
 *
 * ressortgroupref is used in the representation of ORDER BY, GROUP BY, and
 * DISTINCT items.  Targetlist entries with ressortgroupref=0 are not
 * sort/group items.  If ressortgroupref>0, then this item is an ORDER BY,
 * GROUP BY, and/or DISTINCT target value.  No two entries in a targetlist
 * may have the same nonzero ressortgroupref --- but there is no particular
 * meaning to the nonzero values, except as tags.  (For example, one must
 * not assume that lower ressortgroupref means a more significant sort key.)
 * The order of the associated PGSortGroupClause lists determine the semantics.
 *
 * resorigtbl/resorigcol identify the source of the column, if it is a
 * simple reference to a column of a base table (or view).  If it is not
 * a simple reference, these fields are zeroes.
 *
 * If resjunk is true then the column is a working column (such as a sort key)
 * that should be removed from the final output of the query.  Resjunk columns
 * must have resnos that cannot duplicate any regular column's resno.  Also
 * note that there are places that assume resjunk columns come after non-junk
 * columns.
 *--------------------
 */
typedef struct PGTargetEntry {
	PGExpr xpr;
	PGExpr *expr;            /* expression to evaluate */
	PGAttrNumber resno;      /* attribute number (see notes above) */
	char *resname;           /* name of the column (could be NULL) */
	PGIndex ressortgroupref; /* nonzero if referenced by a sort/group
									 * clause */
	PGOid resorigtbl;        /* OID of column's source table */
	PGAttrNumber resorigcol; /* column's number in source table */
	bool resjunk;            /* set to true to eliminate the attribute from
								 * final target list */
} PGTargetEntry;

/* ----------------------------------------------------------------
 *					node types for join trees
 *
 * The leaves of a join tree structure are PGRangeTblRef nodes.  Above
 * these, PGJoinExpr nodes can appear to denote a specific kind of join
 * or qualified join.  Also, PGFromExpr nodes can appear to denote an
 * ordinary cross-product join ("FROM foo, bar, baz WHERE ...").
 * PGFromExpr is like a PGJoinExpr of jointype PG_JOIN_INNER, except that it
 * may have any number of child nodes, not just two.
 *
 * NOTE: the top level of a Query's jointree is always a FromExpr.
 * Even if the jointree contains no rels, there will be a FromExpr.
 *
 * NOTE: the qualification expressions present in PGJoinExpr nodes are
 * *in addition to* the query's main WHERE clause, which appears as the
 * qual of the top-level FromExpr.  The reason for associating quals with
 * specific nodes in the jointree is that the position of a qual is critical
 * when outer joins are present.  (If we enforce a qual too soon or too late,
 * that may cause the outer join to produce the wrong set of NULL-extended
 * rows.)  If all joins are inner joins then all the qual positions are
 * semantically interchangeable.
 *
 * NOTE: in the raw output of gram.y, a join tree contains PGRangeVar,
 * PGRangeSubselect, and PGRangeFunction nodes, which are all replaced by
 * PGRangeTblRef nodes during the parse analysis phase.  Also, the top-level
 * PGFromExpr is added during parse analysis; the grammar regards FROM and
 * WHERE as separate.
 * ----------------------------------------------------------------
 */

/*
 * PGRangeTblRef - reference to an entry in the query's rangetable
 *
 * We could use direct pointers to the RT entries and skip having these
 * nodes, but multiple pointers to the same node in a querytree cause
 * lots of headaches, so it seems better to store an index into the RT.
 */
typedef struct PGRangeTblRef {
	PGNodeTag type;
	int rtindex;
} PGRangeTblRef;

/*----------
 * PGJoinExpr - for SQL JOIN expressions
 *
 * isNatural, usingClause, and quals are interdependent.  The user can write
 * only one of NATURAL, USING(), or ON() (this is enforced by the grammar).
 * If he writes NATURAL then parse analysis generates the equivalent USING()
 * list, and from that fills in "quals" with the right equality comparisons.
 * If he writes USING() then "quals" is filled with equality comparisons.
 * If he writes ON() then only "quals" is set.  Note that NATURAL/USING
 * are not equivalent to ON() since they also affect the output column list.
 *
 * alias is an PGAlias node representing the AS alias-clause attached to the
 * join expression, or NULL if no clause.  NB: presence or absence of the
 * alias has a critical impact on semantics, because a join with an alias
 * restricts visibility of the tables/columns inside it.
 *
 * During parse analysis, an RTE is created for the PGJoin, and its index
 * is filled into rtindex.  This RTE is present mainly so that Vars can
 * be created that refer to the outputs of the join.  The planner sometimes
 * generates JoinExprs internally; these can have rtindex = 0 if there are
 * no join alias variables referencing such joins.
 *----------
 */
typedef struct PGJoinExpr {
	PGNodeTag type;
	PGJoinType jointype; /* type of join */
	bool isNatural;      /* Natural join? Will need to shape table */
	PGNode *larg;        /* left subtree */
	PGNode *rarg;        /* right subtree */
	PGList *usingClause; /* USING clause, if any (list of String) */
	PGNode *quals;       /* qualifiers on join, if any */
	PGAlias *alias;      /* user-written alias clause, if any */
	int rtindex;         /* RT index assigned for join, or 0 */
	int location;          /* token location, or -1 if unknown */
} PGJoinExpr;

/*----------
 * PGFromExpr - represents a FROM ... WHERE ... construct
 *
 * This is both more flexible than a PGJoinExpr (it can have any number of
 * children, including zero) and less so --- we don't need to deal with
 * aliases and so on.  The output column set is implicitly just the union
 * of the outputs of the children.
 *----------
 */
typedef struct PGFromExpr {
	PGNodeTag type;
	PGList *fromlist; /* PGList of join subtrees */
	PGNode *quals;    /* qualifiers on join, if any */
} PGFromExpr;

/*----------
 * PGOnConflictExpr - represents an ON CONFLICT DO ... expression
 *
 * The optimizer requires a list of inference elements, and optionally a WHERE
 * clause to infer a unique index.  The unique index (or, occasionally,
 * indexes) inferred are used to arbitrate whether or not the alternative ON
 * CONFLICT path is taken.
 *----------
 */
typedef struct PGOnConflictExpr {
	PGNodeTag type;
	PGOnConflictAction action; /* DO NOTHING or UPDATE? */

	/* Arbiter */
	PGList *arbiterElems; /* unique index arbiter list (of
								 * InferenceElem's) */
	PGNode *arbiterWhere; /* unique index arbiter WHERE clause */
	PGOid constraint;     /* pg_constraint OID for arbiter */

	/* ON CONFLICT UPDATE */
	PGList *onConflictSet;   /* PGList of ON CONFLICT SET TargetEntrys */
	PGNode *onConflictWhere; /* qualifiers to restrict UPDATE to */
	int exclRelIndex;        /* RT index of 'excluded' relation */
	PGList *exclRelTlist;    /* tlist of the EXCLUDED pseudo relation */
} PGOnConflictExpr;

}

// LICENSE_CHANGE_END



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * value.h
 *	  interface for PGValue nodes
 *
 *
 * Copyright (c) 2003-2017, PostgreSQL Global Development PGGroup
 *
 * src/include/nodes/value.h
 *
 *-------------------------------------------------------------------------
 */





namespace duckdb_libpgquery {

/*----------------------
 *		PGValue node
 *
 * The same PGValue struct is used for five node types: duckdb_libpgquery::T_PGInteger,
 * duckdb_libpgquery::T_PGFloat, duckdb_libpgquery::T_PGString, duckdb_libpgquery::T_PGBitString, T_Null.
 *
 * Integral values are actually represented by a machine integer,
 * but both floats and strings are represented as strings.
 * Using duckdb_libpgquery::T_PGFloat as the node type simply indicates that
 * the contents of the string look like a valid numeric literal.
 *
 * (Before Postgres 7.0, we used a double to represent duckdb_libpgquery::T_PGFloat,
 * but that creates loss-of-precision problems when the value is
 * ultimately destined to be converted to NUMERIC.  Since PGValue nodes
 * are only used in the parsing process, not for runtime data, it's
 * better to use the more general representation.)
 *
 * Note that an integer-looking string will get lexed as duckdb_libpgquery::T_PGFloat if
 * the value is too large to fit in a 'long'.
 *
 * Nulls, of course, don't need the value part at all.
 *----------------------
 */
typedef struct PGValue {
	PGNodeTag type; /* tag appropriately (eg. duckdb_libpgquery::T_PGString) */
	union ValUnion {
		long ival; /* machine integer */
		char *str; /* string */
	} val;
} PGValue;

#define intVal(v) (((PGValue *)(v))->val.ival)
#define floatVal(v) atof(((PGValue *)(v))->val.str)
#define strVal(v) (((PGValue *)(v))->val.str)

PGValue *makeInteger(long i);
PGValue *makeFloat(char *numericStr);
PGValue *makeString(const char *str);
PGValue *makeBitString(char *str);

}

// LICENSE_CHANGE_END


namespace duckdb_libpgquery {

typedef enum PGOverridingKind {
	PG_OVERRIDING_NOT_SET = 0,
	PG_OVERRIDING_USER_VALUE,
	OVERRIDING_SYSTEM_VALUE
} PGOverridingKind;

/* Possible sources of a PGQuery */
typedef enum PGQuerySource {
	PG_QSRC_ORIGINAL,          /* original parsetree (explicit query) */
	PG_QSRC_PARSER,            /* added by parse analysis (now unused) */
	PG_QSRC_INSTEAD_RULE,      /* added by unconditional INSTEAD rule */
	PG_QSRC_QUAL_INSTEAD_RULE, /* added by conditional INSTEAD rule */
	QSRC_NON_INSTEAD_RULE      /* added by non-INSTEAD rule */
} PGQuerySource;

/* PGSort ordering options for ORDER BY and CREATE INDEX */
typedef enum PGSortByDir {
	PG_SORTBY_DEFAULT,
	PG_SORTBY_ASC,
	PG_SORTBY_DESC,
	SORTBY_USING /* not allowed in CREATE INDEX ... */
} PGSortByDir;

typedef enum PGSortByNulls { PG_SORTBY_NULLS_DEFAULT, PG_SORTBY_NULLS_FIRST, PG_SORTBY_NULLS_LAST } PGSortByNulls;

/*****************************************************************************
 *	PGQuery Tree
 *****************************************************************************/

/*
 * PGQuery -
 *	  Parse analysis turns all statements into a PGQuery tree
 *	  for further processing by the rewriter and planner.
 *
 *	  Utility statements (i.e. non-optimizable statements) have the
 *	  utilityStmt field set, and the rest of the PGQuery is mostly dummy.
 *
 *	  Planning converts a PGQuery tree into a PGPlan tree headed by a PGPlannedStmt
 *	  node --- the PGQuery structure is not used by the executor.
 */
typedef struct PGQuery {
	PGNodeTag type;

	PGCmdType commandType; /* select|insert|update|delete|utility */

	PGQuerySource querySource; /* where did I come from? */

	uint32_t queryId; /* query identifier (can be set by plugins) */

	bool canSetTag; /* do I set the command result tag? */

	PGNode *utilityStmt; /* non-null if commandType == PG_CMD_UTILITY */

	int resultRelation; /* rtable index of target relation for
								 * INSERT/UPDATE/DELETE; 0 for SELECT */

	bool hasAggs;         /* has aggregates in tlist or havingQual */
	bool hasWindowFuncs;  /* has window functions in tlist */
	bool hasTargetSRFs;   /* has set-returning functions in tlist */
	bool hasSubLinks;     /* has subquery PGSubLink */
	bool hasDistinctOn;   /* distinctClause is from DISTINCT ON */
	bool hasRecursive;    /* WITH RECURSIVE was specified */
	bool hasModifyingCTE; /* has INSERT/UPDATE/DELETE in WITH */
	bool hasForUpdate;    /* FOR [KEY] UPDATE/SHARE was specified */
	bool hasRowSecurity;  /* rewriter has applied some RLS policy */

	PGList *cteList; /* WITH list (of CommonTableExpr's) */

	PGList *rtable;       /* list of range table entries */
	PGFromExpr *jointree; /* table join tree (FROM and WHERE clauses) */

	PGList *targetList; /* target list (of PGTargetEntry) */

	PGOverridingKind override; /* OVERRIDING clause */

	PGOnConflictExpr *onConflict; /* ON CONFLICT DO [NOTHING | UPDATE] */

	PGList *returningList; /* return-values list (of PGTargetEntry) */

	PGList *groupClause; /* a list of SortGroupClause's */

	PGList *groupingSets; /* a list of GroupingSet's if present */

	PGNode *havingQual; /* qualifications applied to groups */

	PGList *windowClause; /* a list of WindowClause's */

	PGList *distinctClause; /* a list of SortGroupClause's */

	PGList *sortClause; /* a list of SortGroupClause's */

	PGNode *limitOffset; /* # of result tuples to skip (int8_t expr) */
	PGNode *limitCount;  /* # of result tuples to return (int8_t expr) */

	PGList *rowMarks; /* a list of RowMarkClause's */

	PGNode *setOperations; /* set-operation tree if this is top level of
								 * a UNION/INTERSECT/EXCEPT query */

	PGList *constraintDeps; /* a list of pg_constraint OIDs that the query
								 * depends on to be semantically valid */

	PGList *withCheckOptions; /* a list of WithCheckOption's, which are
									 * only added during rewrite and therefore
									 * are not written out as part of Query. */

	/*
	 * The following two fields identify the portion of the source text string
	 * containing this query.  They are typically only populated in top-level
	 * Queries, not in sub-queries.  When not set, they might both be zero, or
	 * both be -1 meaning "unknown".
	 */
	int stmt_location; /* start location, or -1 if unknown */
	int stmt_len;      /* length in bytes; 0 means "rest of string" */
} PGQuery;

/****************************************************************************
 *	Supporting data structures for Parse Trees
 *
 *	Most of these node types appear in raw parsetrees output by the grammar,
 *	and get transformed to something else by the analyzer.  A few of them
 *	are used as-is in transformed querytrees.
 ****************************************************************************/

/*
 * PGTypeName - specifies a type in definitions
 *
 * For PGTypeName structures generated internally, it is often easier to
 * specify the type by OID than by name.  If "names" is NIL then the
 * actual type OID is given by typeOid, otherwise typeOid is unused.
 * Similarly, if "typmods" is NIL then the actual typmod is expected to
 * be prespecified in typemod, otherwise typemod is unused.
 *
 * If pct_type is true, then names is actually a field name and we look up
 * the type of that field.  Otherwise (the normal case), names is a type
 * name possibly qualified with schema and database name.
 */
typedef struct PGTypeName {
	PGNodeTag type;
	PGList *names;       /* qualified name (list of PGValue strings) */
	PGOid typeOid;       /* type identified by OID */
	bool setof;          /* is a set? */
	bool pct_type;       /* %TYPE specified? */
	PGList *typmods;     /* type modifier expression(s) */
	int32_t typemod;     /* prespecified type modifier */
	PGList *arrayBounds; /* array bounds */
	int location;        /* token location, or -1 if unknown */
} PGTypeName;

/*
 * PGColumnRef - specifies a reference to a column, or possibly a whole tuple
 *
 * The "fields" list must be nonempty.  It can contain string PGValue nodes
 * (representing names) and PGAStar nodes (representing occurrence of a '*').
 * Currently, PGAStar must appear only as the last list element --- the grammar
 * is responsible for enforcing this!
 *
 * Note: any array subscripting or selection of fields from composite columns
 * is represented by an PGAIndirection node above the ColumnRef.  However,
 * for simplicity in the normal case, initial field selection from a table
 * name is represented within PGColumnRef and not by adding AIndirection.
 */
typedef struct PGColumnRef {
	PGNodeTag type;
	PGList *fields;       /* field names (PGValue strings) or PGAStar */
	int location;         /* token location, or -1 if unknown */
} PGColumnRef;

/*
 * PGParamRef - specifies a $n parameter reference
 */
typedef struct PGParamRef {
	PGNodeTag type;
	int number;   /* the number of the parameter */
	int location; /* token location, or -1 if unknown */
} PGParamRef;

/*
 * PGAExpr - infix, prefix, and postfix expressions
 */
typedef enum PGAExpr_Kind {
	PG_AEXPR_OP,              /* normal operator */
	PG_AEXPR_OP_ANY,          /* scalar op ANY (array) */
	PG_AEXPR_OP_ALL,          /* scalar op ALL (array) */
	PG_AEXPR_DISTINCT,        /* IS DISTINCT FROM - name must be "=" */
	PG_AEXPR_NOT_DISTINCT,    /* IS NOT DISTINCT FROM - name must be "=" */
	PG_AEXPR_NULLIF,          /* NULLIF - name must be "=" */
	PG_AEXPR_OF,              /* IS [NOT] OF - name must be "=" or "<>" */
	PG_AEXPR_IN,              /* [NOT] IN - name must be "=" or "<>" */
	PG_AEXPR_LIKE,            /* [NOT] LIKE - name must be "~~" or "!~~" */
	PG_AEXPR_ILIKE,           /* [NOT] ILIKE - name must be "~~*" or "!~~*" */
	PG_AEXPR_GLOB,            /* [NOT] GLOB - name must be "~~~" or "!~~~" */
	PG_AEXPR_SIMILAR,         /* [NOT] SIMILAR - name must be "~" or "!~" */
	PG_AEXPR_BETWEEN,         /* name must be "BETWEEN" */
	PG_AEXPR_NOT_BETWEEN,     /* name must be "NOT BETWEEN" */
	PG_AEXPR_BETWEEN_SYM,     /* name must be "BETWEEN SYMMETRIC" */
	PG_AEXPR_NOT_BETWEEN_SYM, /* name must be "NOT BETWEEN SYMMETRIC" */
	AEXPR_PAREN               /* nameless dummy node for parentheses */
} PGAExpr_Kind;

typedef struct PGAExpr {
	PGNodeTag type;
	PGAExpr_Kind kind; /* see above */
	PGList *name;      /* possibly-qualified name of operator */
	PGNode *lexpr;     /* left argument, or NULL if none */
	PGNode *rexpr;     /* right argument, or NULL if none */
	int location;      /* token location, or -1 if unknown */
} PGAExpr;

/*
 * PGAConst - a literal constant
 */
typedef struct PGAConst {
	PGNodeTag type;
	PGValue val;  /* value (includes type info, see value.h) */
	int location; /* token location, or -1 if unknown */
} PGAConst;

/*
 * PGTypeCast - a CAST expression
 */
typedef struct PGTypeCast {
	PGNodeTag type;
	PGNode *arg;          /* the expression being casted */
	PGTypeName *typeName; /* the target type */
	int tryCast;          /* TRY_CAST or CAST */
	int location;         /* token location, or -1 if unknown */
} PGTypeCast;

/*
 * PGCollateClause - a COLLATE expression
 */
typedef struct PGCollateClause {
	PGNodeTag type;
	PGNode *arg;      /* input expression */
	PGList *collname; /* possibly-qualified collation name */
	int location;     /* token location, or -1 if unknown */
} PGCollateClause;

/*
 * PGFuncCall - a function or aggregate invocation
 *
 * agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
 * agg_within_group is true, it was 'foo(...) WITHIN GROUP (ORDER BY ...)'.
 * agg_star indicates we saw a 'foo(*)' construct, while agg_distinct
 * indicates we saw 'foo(DISTINCT ...)'.  In any of these cases, the
 * construct *must* be an aggregate call.  Otherwise, it might be either an
 * aggregate or some other kind of function.  However, if FILTER or OVER is
 * present it had better be an aggregate or window function.
 *
 * Normally, you'd initialize this via makeFuncCall() and then only change the
 * parts of the struct its defaults don't match afterwards, as needed.
 */
typedef struct PGFuncCall {
	PGNodeTag type;
	PGList *funcname;         /* qualified name of function */
	PGList *args;             /* the arguments (list of exprs) */
	PGList *agg_order;        /* ORDER BY (list of PGSortBy) */
	PGNode *agg_filter;       /* FILTER clause, if any */
	bool export_state;        /* EXPORT_STATE clause, if any */
	bool agg_within_group;    /* ORDER BY appeared in WITHIN GROUP */
	bool agg_star;            /* argument was really '*' */
	bool agg_distinct;        /* arguments were labeled DISTINCT */
	bool agg_ignore_nulls;    /* arguments were labeled IGNORE NULLS */
	bool func_variadic;       /* last argument was labeled VARIADIC */
	struct PGWindowDef *over; /* OVER clause, if any */
	int location;             /* token location, or -1 if unknown */
} PGFuncCall;

/*
 * PGAStar - '*' representing all columns of a table or compound field
 *
 * This can appear within ColumnRef.fields, AIndirection.indirection, and
 * ResTarget.indirection lists.
 */
typedef struct PGAStar {
	PGNodeTag type;
	char *relation;       /* relation name (optional) */
	PGList *except_list;  /* optional: EXCLUDE list */
	PGList *replace_list; /* optional: REPLACE list */
} PGAStar;

/*
 * PGAIndices - array subscript or slice bounds ([idx] or [lidx:uidx])
 *
 * In slice case, either or both of lidx and uidx can be NULL (omitted).
 * In non-slice case, uidx holds the single subscript and lidx is always NULL.
 */
typedef struct PGAIndices {
	PGNodeTag type;
	bool is_slice; /* true if slice (i.e., colon present) */
	PGNode *lidx;  /* slice lower bound, if any */
	PGNode *uidx;  /* subscript, or slice upper bound if any */
} PGAIndices;

/*
 * PGAIndirection - select a field and/or array element from an expression
 *
 * The indirection list can contain PGAIndices nodes (representing
 * subscripting), string PGValue nodes (representing field selection --- the
 * string value is the name of the field to select), and PGAStar nodes
 * (representing selection of all fields of a composite type).
 * For example, a complex selection operation like
 *				(foo).field1[42][7].field2
 * would be represented with a single PGAIndirection node having a 4-element
 * indirection list.
 *
 * Currently, PGAStar must appear only as the last list element --- the grammar
 * is responsible for enforcing this!
 */
typedef struct PGAIndirection {
	PGNodeTag type;
	PGNode *arg;         /* the thing being selected from */
	PGList *indirection; /* subscripts and/or field names and/or * */
} PGAIndirection;

/*
 * PGAArrayExpr - an ARRAY[] construct
 */
typedef struct PGAArrayExpr {
	PGNodeTag type;
	PGList *elements; /* array element expressions */
	int location;     /* token location, or -1 if unknown */
} PGAArrayExpr;

/*
 * PGResTarget -
 *	  result target (used in target list of pre-transformed parse trees)
 *
 * In a SELECT target list, 'name' is the column label from an
 * 'AS ColumnLabel' clause, or NULL if there was none, and 'val' is the
 * value expression itself.  The 'indirection' field is not used.
 *
 * INSERT uses PGResTarget in its target-column-names list.  Here, 'name' is
 * the name of the destination column, 'indirection' stores any subscripts
 * attached to the destination, and 'val' is not used.
 *
 * In an UPDATE target list, 'name' is the name of the destination column,
 * 'indirection' stores any subscripts attached to the destination, and
 * 'val' is the expression to assign.
 *
 * See PGAIndirection for more info about what can appear in 'indirection'.
 */
typedef struct PGResTarget {
	PGNodeTag type;
	char *name;          /* column name or NULL */
	PGList *indirection; /* subscripts, field names, and '*', or NIL */
	PGNode *val;         /* the value expression to compute or assign */
	int location;        /* token location, or -1 if unknown */
} PGResTarget;

/*
 * PGMultiAssignRef - element of a row source expression for UPDATE
 *
 * In an UPDATE target list, when we have SET (a,b,c) = row-valued-expression,
 * we generate separate PGResTarget items for each of a,b,c.  Their "val" trees
 * are PGMultiAssignRef nodes numbered 1..n, linking to a common copy of the
 * row-valued-expression (which parse analysis will process only once, when
 * handling the PGMultiAssignRef with colno=1).
 */
typedef struct PGMultiAssignRef {
	PGNodeTag type;
	PGNode *source; /* the row-valued expression */
	int colno;      /* column number for this target (1..n) */
	int ncolumns;   /* number of targets in the construct */
} PGMultiAssignRef;

/*
 * PGSortBy - for ORDER BY clause
 */
typedef struct PGSortBy {
	PGNodeTag type;
	PGNode *node;               /* expression to sort on */
	PGSortByDir sortby_dir;     /* ASC/DESC/USING/default */
	PGSortByNulls sortby_nulls; /* NULLS FIRST/LAST */
	PGList *useOp;              /* name of op to use, if SORTBY_USING */
	int location;               /* operator location, or -1 if none/unknown */
} PGSortBy;

/*
 * PGWindowDef - raw representation of WINDOW and OVER clauses
 *
 * For entries in a WINDOW list, "name" is the window name being defined.
 * For OVER clauses, we use "name" for the "OVER window" syntax, or "refname"
 * for the "OVER (window)" syntax, which is subtly different --- the latter
 * implies overriding the window frame clause.
 */
typedef struct PGWindowDef {
	PGNodeTag type;
	char *name;              /* window's own name */
	char *refname;           /* referenced window name, if any */
	PGList *partitionClause; /* PARTITION BY expression list */
	PGList *orderClause;     /* ORDER BY (list of PGSortBy) */
	int frameOptions;        /* frame_clause options, see below */
	PGNode *startOffset;     /* expression for starting bound, if any */
	PGNode *endOffset;       /* expression for ending bound, if any */
	int location;            /* parse location, or -1 if none/unknown */
} PGWindowDef;

/*
 * frameOptions is an OR of these bits.  The NONDEFAULT and BETWEEN bits are
 * used so that ruleutils.c can tell which properties were specified and
 * which were defaulted; the correct behavioral bits must be set either way.
 * The START_foo and END_foo options must come in pairs of adjacent bits for
 * the convenience of gram.y, even though some of them are useless/invalid.
 * We will need more bits (and fields) to cover the full SQL:2008 option set.
 */
#define FRAMEOPTION_NONDEFAULT 0x00001 /* any specified? */
#define FRAMEOPTION_RANGE 0x00002 /* RANGE behavior */
#define FRAMEOPTION_ROWS 0x00004 /* ROWS behavior */
#define FRAMEOPTION_BETWEEN 0x00008 /* BETWEEN given? */
#define FRAMEOPTION_START_UNBOUNDED_PRECEDING 0x00010 /* start is U. P. */
#define FRAMEOPTION_END_UNBOUNDED_PRECEDING 0x00020 /* (disallowed) */
#define FRAMEOPTION_START_UNBOUNDED_FOLLOWING 0x00040 /* (disallowed) */
#define FRAMEOPTION_END_UNBOUNDED_FOLLOWING 0x00080 /* end is U. F. */
#define FRAMEOPTION_START_CURRENT_ROW 0x00100 /* start is C. R. */
#define FRAMEOPTION_END_CURRENT_ROW 0x00200 /* end is C. R. */
#define FRAMEOPTION_START_VALUE_PRECEDING 0x00400 /* start is V. P. */
#define FRAMEOPTION_END_VALUE_PRECEDING 0x00800 /* end is V. P. */
#define FRAMEOPTION_START_VALUE_FOLLOWING 0x01000 /* start is V. F. */
#define FRAMEOPTION_END_VALUE_FOLLOWING 0x02000 /* end is V. F. */

#define FRAMEOPTION_START_VALUE (FRAMEOPTION_START_VALUE_PRECEDING | FRAMEOPTION_START_VALUE_FOLLOWING)
#define FRAMEOPTION_END_VALUE (FRAMEOPTION_END_VALUE_PRECEDING | FRAMEOPTION_END_VALUE_FOLLOWING)

#define FRAMEOPTION_DEFAULTS (FRAMEOPTION_RANGE | FRAMEOPTION_START_UNBOUNDED_PRECEDING | FRAMEOPTION_END_CURRENT_ROW)

/*
 * PGRangeSubselect - subquery appearing in a FROM clause
 */
typedef struct PGRangeSubselect {
	PGNodeTag type;
	bool lateral;     /* does it have LATERAL prefix? */
	PGNode *subquery; /* the untransformed sub-select clause */
	PGAlias *alias;   /* table alias & optional column aliases */
	PGNode *sample;   /* sample options (if any) */
} PGRangeSubselect;

/*
 * PGRangeFunction - function call appearing in a FROM clause
 *
 * functions is a PGList because we use this to represent the construct
 * ROWS FROM(func1(...), func2(...), ...).  Each element of this list is a
 * two-element sublist, the first element being the untransformed function
 * call tree, and the second element being a possibly-empty list of PGColumnDef
 * nodes representing any columndef list attached to that function within the
 * ROWS FROM() syntax.
 *
 * alias and coldeflist represent any alias and/or columndef list attached
 * at the top level.  (We disallow coldeflist appearing both here and
 * per-function, but that's checked in parse analysis, not by the grammar.)
 */
typedef struct PGRangeFunction {
	PGNodeTag type;
	bool lateral;       /* does it have LATERAL prefix? */
	bool ordinality;    /* does it have WITH ORDINALITY suffix? */
	bool is_rowsfrom;   /* is result of ROWS FROM() syntax? */
	PGList *functions;  /* per-function information, see above */
	PGAlias *alias;     /* table alias & optional column aliases */
	PGList *coldeflist; /* list of PGColumnDef nodes to describe result
								 * of function returning RECORD */
	PGNode *sample;   /* sample options (if any) */
} PGRangeFunction;

/* Category of the column */
typedef enum ColumnCategory {
	COL_STANDARD,	/* regular column */
	COL_GENERATED	/* generated (VIRTUAL|STORED) */
}	ColumnCategory;

/*
 * PGColumnDef - column definition (used in various creates)
 *
 * If the column has a default value, we may have the value expression
 * in either "raw" form (an untransformed parse tree) or "cooked" form
 * (a post-parse-analysis, executable expression tree), depending on
 * how this PGColumnDef node was created (by parsing, or by inheritance
 * from an existing relation).  We should never have both in the same node!
 *
 * Similarly, we may have a COLLATE specification in either raw form
 * (represented as a PGCollateClause with arg==NULL) or cooked form
 * (the collation's OID).
 *
 * The constraints list may contain a PG_CONSTR_DEFAULT item in a raw
 * parsetree produced by gram.y, but transformCreateStmt will remove
 * the item and set raw_default instead.  PG_CONSTR_DEFAULT items
 * should not appear in any subsequent processing.
 */

typedef struct PGColumnDef {
	PGNodeTag type;               /* ENSURES COMPATIBILITY WITH 'PGNode' - has to be first line */
	char *colname;                /* name of column */
	PGTypeName *typeName;         /* type of column */
	int inhcount;                 /* number of times column is inherited */
	bool is_local;                /* column has local (non-inherited) def'n */
	bool is_not_null;             /* NOT NULL constraint specified? */
	bool is_from_type;            /* column definition came from table type */
	bool is_from_parent;          /* column def came from partition parent */
	char storage;                 /* attstorage setting, or 0 for default */
	PGNode *raw_default;          /* default value (untransformed parse tree) */
	PGNode *cooked_default;       /* default value (transformed expr tree) */
	char identity;                /* attidentity setting */
	PGRangeVar *identitySequence; /* to store identity sequence name for ALTER
								   * TABLE ... ADD COLUMN */
	PGCollateClause *collClause;  /* untransformed COLLATE spec, if any */
	PGOid collOid;                /* collation OID (InvalidOid if not set) */
	PGList *constraints;          /* other constraints on column */
	PGList *fdwoptions;           /* per-column FDW options */
	int location;                 /* parse location, or -1 if none/unknown */
	ColumnCategory category;	  /* category of the column */
} PGColumnDef;

/*
 * PGTableLikeClause - CREATE TABLE ( ... LIKE ... ) clause
 */
typedef struct PGTableLikeClause {
	PGNodeTag type;
	PGRangeVar *relation;
	uint32_t options; /* OR of PGTableLikeOption flags */
} PGTableLikeClause;

typedef enum PGTableLikeOption {
	PG_CREATE_TABLE_LIKE_DEFAULTS = 1 << 0,
	PG_CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 1,
	PG_CREATE_TABLE_LIKE_IDENTITY = 1 << 2,
	PG_CREATE_TABLE_LIKE_INDEXES = 1 << 3,
	PG_CREATE_TABLE_LIKE_STORAGE = 1 << 4,
	PG_CREATE_TABLE_LIKE_COMMENTS = 1 << 5,
	PG_CREATE_TABLE_LIKE_STATISTICS = 1 << 6,
	PG_CREATE_TABLE_LIKE_ALL = INT_MAX
} PGTableLikeOption;

/*
 * PGIndexElem - index parameters (used in CREATE INDEX, and in ON CONFLICT)
 *
 * For a plain index attribute, 'name' is the name of the table column to
 * index, and 'expr' is NULL.  For an index expression, 'name' is NULL and
 * 'expr' is the expression tree.
 */
typedef struct PGIndexElem {
	PGNodeTag type;
	char *name;                   /* name of attribute to index, or NULL */
	PGNode *expr;                 /* expression to index, or NULL */
	char *indexcolname;           /* name for index column; NULL = default */
	PGList *collation;            /* name of collation; NIL = default */
	PGList *opclass;              /* name of desired opclass; NIL = default */
	PGSortByDir ordering;         /* ASC/DESC/default */
	PGSortByNulls nulls_ordering; /* FIRST/LAST/default */
} PGIndexElem;

/*
 * PGDefElem - a generic "name = value" option definition
 *
 * In some contexts the name can be qualified.  Also, certain SQL commands
 * allow a SET/ADD/DROP action to be attached to option settings, so it's
 * convenient to carry a field for that too.  (Note: currently, it is our
 * practice that the grammar allows namespace and action only in statements
 * where they are relevant; C code can just ignore those fields in other
 * statements.)
 */
typedef enum PGDefElemAction {
	PG_DEFELEM_UNSPEC, /* no action given */
	PG_DEFELEM_SET,
	PG_DEFELEM_ADD,
	DEFELEM_DROP
} PGDefElemAction;

typedef struct PGDefElem {
	PGNodeTag type;
	char *defnamespace; /* NULL if unqualified name */
	char *defname;
	PGNode *arg;               /* a (PGValue *) or a (PGTypeName *) */
	PGDefElemAction defaction; /* unspecified action, or SET/ADD/DROP */
	int location;              /* token location, or -1 if unknown */
} PGDefElem;

/*
 * PGLockingClause - raw representation of FOR [NO KEY] UPDATE/[KEY] SHARE
 *		options
 *
 * Note: lockedRels == NIL means "all relations in query".  Otherwise it
 * is a list of PGRangeVar nodes.  (We use PGRangeVar mainly because it carries
 * a location field --- currently, parse analysis insists on unqualified
 * names in LockingClause.)
 */
typedef struct PGLockingClause {
	PGNodeTag type;
	PGList *lockedRels; /* FOR [KEY] UPDATE/SHARE relations */
	PGLockClauseStrength strength;
	PGLockWaitPolicy waitPolicy; /* NOWAIT and SKIP LOCKED */
} PGLockingClause;

/****************************************************************************
 *	Nodes for a PGQuery tree
 ****************************************************************************/

/*--------------------
 * PGRangeTblEntry -
 *	  A range table is a PGList of PGRangeTblEntry nodes.
 *
 *	  A range table entry may represent a plain relation, a sub-select in
 *	  FROM, or the result of a JOIN clause.  (Only explicit JOIN syntax
 *	  produces an RTE, not the implicit join resulting from multiple FROM
 *	  items.  This is because we only need the RTE to deal with SQL features
 *	  like outer joins and join-output-column aliasing.)  Other special
 *	  RTE types also exist, as indicated by RTEKind.
 *
 *	  Note that we consider PG_RTE_RELATION to cover anything that has a pg_class
 *	  entry.  relkind distinguishes the sub-cases.
 *
 *	  alias is an PGAlias node representing the AS alias-clause attached to the
 *	  FROM expression, or NULL if no clause.
 *
 *	  eref is the table reference name and column reference names (either
 *	  real or aliases).  Note that system columns (OID etc) are not included
 *	  in the column list.
 *	  eref->aliasname is required to be present, and should generally be used
 *	  to identify the RTE for error messages etc.
 *
 *	  In RELATION RTEs, the colnames in both alias and eref are indexed by
 *	  physical attribute number; this means there must be colname entries for
 *	  dropped columns.  When building an RTE we insert empty strings ("") for
 *	  dropped columns.  Note however that a stored rule may have nonempty
 *	  colnames for columns dropped since the rule was created (and for that
 *	  matter the colnames might be out of date due to column renamings).
 *	  The same comments apply to FUNCTION RTEs when a function's return type
 *	  is a named composite type.
 *
 *	  In JOIN RTEs, the colnames in both alias and eref are one-to-one with
 *	  joinaliasvars entries.  A JOIN RTE will omit columns of its inputs when
 *	  those columns are known to be dropped at parse time.  Again, however,
 *	  a stored rule might contain entries for columns dropped since the rule
 *	  was created.  (This is only possible for columns not actually referenced
 *	  in the rule.)  When loading a stored rule, we replace the joinaliasvars
 *	  items for any such columns with null pointers.  (We can't simply delete
 *	  them from the joinaliasvars list, because that would affect the attnums
 *	  of Vars referencing the rest of the list.)
 *
 *	  inh is true for relation references that should be expanded to include
 *	  inheritance children, if the rel has any.  This *must* be false for
 *	  RTEs other than PG_RTE_RELATION entries.
 *
 *	  inFromCl marks those range variables that are listed in the FROM clause.
 *	  It's false for RTEs that are added to a query behind the scenes, such
 *	  as the NEW and OLD variables for a rule, or the subqueries of a UNION.
 *	  This flag is not used anymore during parsing, since the parser now uses
 *	  a separate "namespace" data structure to control visibility, but it is
 *	  needed by ruleutils.c to determine whether RTEs should be shown in
 *	  decompiled queries.
 *--------------------
 */
typedef enum PGRTEKind {
	PG_RTE_RELATION,    /* ordinary relation reference */
	PG_RTE_SUBQUERY,    /* subquery in FROM */
	PG_RTE_JOIN,        /* join */
	PG_RTE_FUNCTION,    /* function in FROM */
	PG_RTE_TABLEFUNC,   /* TableFunc(.., column list) */
	PG_RTE_VALUES,      /* VALUES (<exprlist>), (<exprlist>), ... */
	PG_RTE_CTE,         /* common table expr (WITH list element) */
	RTE_NAMEDTUPLESTORE /* tuplestore, e.g. for AFTER triggers */
} PGRTEKind;

typedef struct PGRangeTblEntry {
	PGNodeTag type;

	PGRTEKind rtekind; /* see above */

	/*
	 * XXX the fields applicable to only some rte kinds should be merged into
	 * a union.  I didn't do this yet because the diffs would impact a lot of
	 * code that is being actively worked on.  FIXME someday.
	 */

	/*
	 * Fields valid for a plain relation RTE (else zero):
	 *
	 * As a special case, RTE_NAMEDTUPLESTORE can also set relid to indicate
	 * that the tuple format of the tuplestore is the same as the referenced
	 * relation.  This allows plans referencing AFTER trigger transition
	 * tables to be invalidated if the underlying table is altered.
	 */
	PGOid relid;                             /* OID of the relation */
	char relkind;                            /* relation kind (see pg_class.relkind) */
	struct PGTableSampleClause *tablesample; /* sampling info, or NULL */

	/*
	 * Fields valid for a subquery RTE (else NULL):
	 */
	PGQuery *subquery; /* the sub-query */

	/*
	 * Fields valid for a join RTE (else NULL/zero):
	 *
	 * joinaliasvars is a list of (usually) Vars corresponding to the columns
	 * of the join result.  An alias PGVar referencing column K of the join
	 * result can be replaced by the K'th element of joinaliasvars --- but to
	 * simplify the task of reverse-listing aliases correctly, we do not do
	 * that until planning time.  In detail: an element of joinaliasvars can
	 * be a PGVar of one of the join's input relations, or such a PGVar with an
	 * implicit coercion to the join's output column type, or a COALESCE
	 * expression containing the two input column Vars (possibly coerced).
	 * Within a PGQuery loaded from a stored rule, it is also possible for
	 * joinaliasvars items to be null pointers, which are placeholders for
	 * (necessarily unreferenced) columns dropped since the rule was made.
	 * Also, once planning begins, joinaliasvars items can be almost anything,
	 * as a result of subquery-flattening substitutions.
	 */
	PGJoinType jointype;   /* type of join */
	PGList *joinaliasvars; /* list of alias-var expansions */

	/*
	 * Fields valid for a function RTE (else NIL/zero):
	 *
	 * When funcordinality is true, the eref->colnames list includes an alias
	 * for the ordinality column.  The ordinality column is otherwise
	 * implicit, and must be accounted for "by hand" in places such as
	 * expandRTE().
	 */
	PGList *functions;   /* list of PGRangeTblFunction nodes */
	bool funcordinality; /* is this called WITH ORDINALITY? */

	/*
	 * Fields valid for a PGTableFunc RTE (else NULL):
	 */
	PGTableFunc *tablefunc;

	/*
	 * Fields valid for a values RTE (else NIL):
	 */
	PGList *values_lists; /* list of expression lists */

	/*
	 * Fields valid for a CTE RTE (else NULL/zero):
	 */
	char *ctename;       /* name of the WITH list item */
	PGIndex ctelevelsup; /* number of query levels up */
	bool self_reference; /* is this a recursive self-reference? */

	/*
	 * Fields valid for table functions, values, CTE and ENR RTEs (else NIL):
	 *
	 * We need these for CTE RTEs so that the types of self-referential
	 * columns are well-defined.  For VALUES RTEs, storing these explicitly
	 * saves having to re-determine the info by scanning the values_lists. For
	 * ENRs, we store the types explicitly here (we could get the information
	 * from the catalogs if 'relid' was supplied, but we'd still need these
	 * for TupleDesc-based ENRs, so we might as well always store the type
	 * info here).
	 *
	 * For ENRs only, we have to consider the possibility of dropped columns.
	 * A dropped column is included in these lists, but it will have zeroes in
	 * all three lists (as well as an empty-string entry in eref).  Testing
	 * for zero coltype is the standard way to detect a dropped column.
	 */
	PGList *coltypes;      /* OID list of column type OIDs */
	PGList *coltypmods;    /* integer list of column typmods */
	PGList *colcollations; /* OID list of column collation OIDs */

	/*
	 * Fields valid for ENR RTEs (else NULL/zero):
	 */
	char *enrname;    /* name of ephemeral named relation */
	double enrtuples; /* estimated or actual from caller */

	/*
	 * Fields valid in all RTEs:
	 */
	PGAlias *alias; /* user-written alias clause, if any */
	PGAlias *eref;  /* expanded reference names */
	bool lateral;   /* subquery, function, or values is LATERAL? */
	bool inh;       /* inheritance requested? */
	bool inFromCl;  /* present in FROM clause? */
} PGRangeTblEntry;

/*
 * PGRangeTblFunction -
 *	  PGRangeTblEntry subsidiary data for one function in a FUNCTION RTE.
 *
 * If the function had a column definition list (required for an
 * otherwise-unspecified RECORD result), funccolnames lists the names given
 * in the definition list, funccoltypes lists their declared column types,
 * funccoltypmods lists their typmods, funccolcollations their collations.
 * Otherwise, those fields are NIL.
 *
 * Notice we don't attempt to store info about the results of functions
 * returning named composite types, because those can change from time to
 * time.  We do however remember how many columns we thought the type had
 * (including dropped columns!), so that we can successfully ignore any
 * columns added after the query was parsed.
 */
typedef struct PGRangeTblFunction {
	PGNodeTag type;

	PGNode *funcexpr; /* expression tree for func call */
	int funccolcount; /* number of columns it contributes to RTE */
	/* These fields record the contents of a column definition list, if any: */
	PGList *funccolnames;      /* column names (list of String) */
	PGList *funccoltypes;      /* OID list of column type OIDs */
	PGList *funccoltypmods;    /* integer list of column typmods */
	PGList *funccolcollations; /* OID list of column collation OIDs */
	/* This is set during planning for use by the executor: */
	PGBitmapset *funcparams; /* PG_PARAM_EXEC PGParam IDs affecting this func */
} PGRangeTblFunction;

/*
 * PGSortGroupClause -
 *		representation of ORDER BY, GROUP BY, PARTITION BY,
 *		DISTINCT, DISTINCT ON items
 *
 * You might think that ORDER BY is only interested in defining ordering,
 * and GROUP/DISTINCT are only interested in defining equality.  However,
 * one way to implement grouping is to sort and then apply a "uniq"-like
 * filter.  So it's also interesting to keep track of possible sort operators
 * for GROUP/DISTINCT, and in particular to try to sort for the grouping
 * in a way that will also yield a requested ORDER BY ordering.  So we need
 * to be able to compare ORDER BY and GROUP/DISTINCT lists, which motivates
 * the decision to give them the same representation.
 *
 * tleSortGroupRef must match ressortgroupref of exactly one entry of the
 *		query's targetlist; that is the expression to be sorted or grouped by.
 * eqop is the OID of the equality operator.
 * sortop is the OID of the ordering operator (a "<" or ">" operator),
 *		or InvalidOid if not available.
 * nulls_first means about what you'd expect.  If sortop is InvalidOid
 *		then nulls_first is meaningless and should be set to false.
 * hashable is true if eqop is hashable (note this condition also depends
 *		on the datatype of the input expression).
 *
 * In an ORDER BY item, all fields must be valid.  (The eqop isn't essential
 * here, but it's cheap to get it along with the sortop, and requiring it
 * to be valid eases comparisons to grouping items.)  Note that this isn't
 * actually enough information to determine an ordering: if the sortop is
 * collation-sensitive, a collation OID is needed too.  We don't store the
 * collation in PGSortGroupClause because it's not available at the time the
 * parser builds the PGSortGroupClause; instead, consult the exposed collation
 * of the referenced targetlist expression to find out what it is.
 *
 * In a grouping item, eqop must be valid.  If the eqop is a btree equality
 * operator, then sortop should be set to a compatible ordering operator.
 * We prefer to set eqop/sortop/nulls_first to match any ORDER BY item that
 * the query presents for the same tlist item.  If there is none, we just
 * use the default ordering op for the datatype.
 *
 * If the tlist item's type has a hash opclass but no btree opclass, then
 * we will set eqop to the hash equality operator, sortop to InvalidOid,
 * and nulls_first to false.  A grouping item of this kind can only be
 * implemented by hashing, and of course it'll never match an ORDER BY item.
 *
 * The hashable flag is provided since we generally have the requisite
 * information readily available when the PGSortGroupClause is constructed,
 * and it's relatively expensive to get it again later.  Note there is no
 * need for a "sortable" flag since OidIsValid(sortop) serves the purpose.
 *
 * A query might have both ORDER BY and DISTINCT (or DISTINCT ON) clauses.
 * In SELECT DISTINCT, the distinctClause list is as long or longer than the
 * sortClause list, while in SELECT DISTINCT ON it's typically shorter.
 * The two lists must match up to the end of the shorter one --- the parser
 * rearranges the distinctClause if necessary to make this true.  (This
 * restriction ensures that only one sort step is needed to both satisfy the
 * ORDER BY and set up for the PGUnique step.  This is semantically necessary
 * for DISTINCT ON, and presents no real drawback for DISTINCT.)
 */
typedef struct PGSortGroupClause {
	PGNodeTag type;
	PGIndex tleSortGroupRef; /* reference into targetlist */
	PGOid eqop;              /* the equality operator ('=' op) */
	PGOid sortop;            /* the ordering operator ('<' op), or 0 */
	bool nulls_first;        /* do NULLs come before normal values? */
	bool hashable;           /* can eqop be implemented by hashing? */
} PGSortGroupClause;

/*
 * PGGroupingSet -
 *		representation of CUBE, ROLLUP and GROUPING SETS clauses
 *
 * In a PGQuery with grouping sets, the groupClause contains a flat list of
 * PGSortGroupClause nodes for each distinct expression used.  The actual
 * structure of the GROUP BY clause is given by the groupingSets tree.
 *
 * In the raw parser output, PGGroupingSet nodes (of all types except SIMPLE
 * which is not used) are potentially mixed in with the expressions in the
 * groupClause of the SelectStmt.  (An expression can't contain a PGGroupingSet,
 * but a list may mix PGGroupingSet and expression nodes.)  At this stage, the
 * content of each node is a list of expressions, some of which may be RowExprs
 * which represent sublists rather than actual row constructors, and nested
 * PGGroupingSet nodes where legal in the grammar.  The structure directly
 * reflects the query syntax.
 *
 * In parse analysis, the transformed expressions are used to build the tlist
 * and groupClause list (of PGSortGroupClause nodes), and the groupingSets tree
 * is eventually reduced to a fixed format:
 *
 * EMPTY nodes represent (), and obviously have no content
 *
 * SIMPLE nodes represent a list of one or more expressions to be treated as an
 * atom by the enclosing structure; the content is an integer list of
 * ressortgroupref values (see PGSortGroupClause)
 *
 * CUBE and ROLLUP nodes contain a list of one or more SIMPLE nodes.
 *
 * SETS nodes contain a list of EMPTY, SIMPLE, CUBE or ROLLUP nodes, but after
 * parse analysis they cannot contain more SETS nodes; enough of the syntactic
 * transforms of the spec have been applied that we no longer have arbitrarily
 * deep nesting (though we still preserve the use of cube/rollup).
 *
 * Note that if the groupingSets tree contains no SIMPLE nodes (only EMPTY
 * nodes at the leaves), then the groupClause will be empty, but this is still
 * an aggregation query (similar to using aggs or HAVING without GROUP BY).
 *
 * As an example, the following clause:
 *
 * GROUP BY GROUPING SETS ((a,b), CUBE(c,(d,e)))
 *
 * looks like this after raw parsing:
 *
 * SETS( RowExpr(a,b) , CUBE( c, RowExpr(d,e) ) )
 *
 * and parse analysis converts it to:
 *
 * SETS( SIMPLE(1,2), CUBE( SIMPLE(3), SIMPLE(4,5) ) )
 */
typedef enum {
	GROUPING_SET_EMPTY,
	GROUPING_SET_SIMPLE,
	GROUPING_SET_ROLLUP,
	GROUPING_SET_CUBE,
	GROUPING_SET_SETS,
	GROUPING_SET_ALL
} GroupingSetKind;

typedef struct PGGroupingSet {
	PGNodeTag type;
	GroupingSetKind kind;
	PGList *content;
	int location;
} PGGroupingSet;

/*
 * PGWindowClause -
 *		transformed representation of WINDOW and OVER clauses
 *
 * A parsed Query's windowClause list contains these structs.  "name" is set
 * if the clause originally came from WINDOW, and is NULL if it originally
 * was an OVER clause (but note that we collapse out duplicate OVERs).
 * partitionClause and orderClause are lists of PGSortGroupClause structs.
 * winref is an ID number referenced by PGWindowFunc nodes; it must be unique
 * among the members of a Query's windowClause list.
 * When refname isn't null, the partitionClause is always copied from there;
 * the orderClause might or might not be copied (see copiedOrder); the framing
 * options are never copied, per spec.
 */
typedef struct PGWindowClause {
	PGNodeTag type;
	char *name;              /* window name (NULL in an OVER clause) */
	char *refname;           /* referenced window name, if any */
	PGList *partitionClause; /* PARTITION BY list */
	PGList *orderClause;     /* ORDER BY list */
	int frameOptions;        /* frame_clause options, see PGWindowDef */
	PGNode *startOffset;     /* expression for starting bound, if any */
	PGNode *endOffset;       /* expression for ending bound, if any */
	PGIndex winref;          /* ID referenced by window functions */
	bool copiedOrder;        /* did we copy orderClause from refname? */
} PGWindowClause;

/*
 * RowMarkClause -
 *	   parser output representation of FOR [KEY] UPDATE/SHARE clauses
 *
 * Query.rowMarks contains a separate RowMarkClause node for each relation
 * identified as a FOR [KEY] UPDATE/SHARE target.  If one of these clauses
 * is applied to a subquery, we generate RowMarkClauses for all normal and
 * subquery rels in the subquery, but they are marked pushedDown = true to
 * distinguish them from clauses that were explicitly written at this query
 * level.  Also, Query.hasForUpdate tells whether there were explicit FOR
 * UPDATE/SHARE/KEY SHARE clauses in the current query level.
 */

/*
 * PGWithClause -
 *	   representation of WITH clause
 *
 * Note: PGWithClause does not propagate into the PGQuery representation;
 * but PGCommonTableExpr does.
 */
typedef struct PGWithClause {
	PGNodeTag type;
	PGList *ctes;   /* list of CommonTableExprs */
	bool recursive; /* true = WITH RECURSIVE */
	int location;   /* token location, or -1 if unknown */
} PGWithClause;

/*
 * PGInferClause -
 *		ON CONFLICT unique index inference clause
 *
 * Note: PGInferClause does not propagate into the PGQuery representation.
 */
typedef struct PGInferClause {
	PGNodeTag type;
	PGList *indexElems;  /* IndexElems to infer unique index */
	PGNode *whereClause; /* qualification (partial-index predicate) */
	char *conname;       /* PGConstraint name, or NULL if unnamed */
	int location;        /* token location, or -1 if unknown */
} PGInferClause;

/*
 * PGOnConflictClause -
 *		representation of ON CONFLICT clause
 *
 * Note: PGOnConflictClause does not propagate into the PGQuery representation.
 */
typedef struct PGOnConflictClause {
	PGNodeTag type;
	PGOnConflictAction action; /* DO NOTHING or UPDATE? */
	PGInferClause *infer;      /* Optional index inference clause */
	PGList *targetList;        /* the target list (of PGResTarget) */
	PGNode *whereClause;       /* qualifications */
	int location;              /* token location, or -1 if unknown */
} PGOnConflictClause;

/*
 * PGCommonTableExpr -
 *	   representation of WITH list element
 *
 * We don't currently support the SEARCH or CYCLE clause.
 */
typedef struct PGCommonTableExpr {
	PGNodeTag type;
	char *ctename;         /* query name (never qualified) */
	PGList *aliascolnames; /* optional list of column names */
	/* SelectStmt/InsertStmt/etc before parse analysis, PGQuery afterwards: */
	PGNode *ctequery; /* the CTE's subquery */
	int location;     /* token location, or -1 if unknown */
	/* These fields are set during parse analysis: */
	bool cterecursive;        /* is this CTE actually recursive? */
	int cterefcount;          /* number of RTEs referencing this CTE
								 * (excluding internal self-references) */
	PGList *ctecolnames;      /* list of output column names */
	PGList *ctecoltypes;      /* OID list of output column type OIDs */
	PGList *ctecoltypmods;    /* integer list of output column typmods */
	PGList *ctecolcollations; /* OID list of column collation OIDs */
} PGCommonTableExpr;

/* Convenience macro to get the output tlist of a CTE's query */
#define GetCTETargetList(cte) \
	(AssertMacro(IsA((cte)->ctequery, PGQuery)), ((PGQuery *)(cte)->ctequery)->commandType == PG_CMD_SELECT ? ((PGQuery *)(cte)->ctequery)->targetList : ((PGQuery *)(cte)->ctequery)->returningList)

/*
 * TriggerTransition -
 *	   representation of transition row or table naming clause
 *
 * Only transition tables are initially supported in the syntax, and only for
 * AFTER triggers, but other permutations are accepted by the parser so we can
 * give a meaningful message from C code.
 */

/*****************************************************************************
 *		Raw Grammar Output Statements
 *****************************************************************************/

/*
 *		PGRawStmt --- container for any one statement's raw parse tree
 *
 * Parse analysis converts a raw parse tree headed by a PGRawStmt node into
 * an analyzed statement headed by a PGQuery node.  For optimizable statements,
 * the conversion is complex.  For utility statements, the parser usually just
 * transfers the raw parse tree (sans PGRawStmt) into the utilityStmt field of
 * the PGQuery node, and all the useful work happens at execution time.
 *
 * stmt_location/stmt_len identify the portion of the source text string
 * containing this raw statement (useful for multi-statement strings).
 */
typedef struct PGRawStmt {
	PGNodeTag type;
	PGNode *stmt;      /* raw parse tree */
	int stmt_location; /* start location, or -1 if unknown */
	int stmt_len;      /* length in bytes; 0 means "rest of string" */
} PGRawStmt;

/*****************************************************************************
 *		Optimizable Statements
 *****************************************************************************/

/* ----------------------
 *		Insert Statement
 *
 * The source expression is represented by PGSelectStmt for both the
 * SELECT and VALUES cases.  If selectStmt is NULL, then the query
 * is INSERT ... DEFAULT VALUES.
 * ----------------------
 */
typedef struct PGInsertStmt {
	PGNodeTag type;
	PGRangeVar *relation;                 /* relation to insert into */
	PGList *cols;                         /* optional: names of the target columns */
	PGNode *selectStmt;                   /* the source SELECT/VALUES, or NULL */
	PGOnConflictClause *onConflictClause; /* ON CONFLICT clause */
	PGList *returningList;                /* list of expressions to return */
	PGWithClause *withClause;             /* WITH clause */
	PGOverridingKind override;            /* OVERRIDING clause */
} PGInsertStmt;

/* ----------------------
 *		Delete Statement
 * ----------------------
 */
typedef struct PGDeleteStmt {
	PGNodeTag type;
	PGRangeVar *relation;     /* relation to delete from */
	PGList *usingClause;      /* optional using clause for more tables */
	PGNode *whereClause;      /* qualifications */
	PGList *returningList;    /* list of expressions to return */
	PGWithClause *withClause; /* WITH clause */
} PGDeleteStmt;

/* ----------------------
 *		Update Statement
 * ----------------------
 */
typedef struct PGUpdateStmt {
	PGNodeTag type;
	PGRangeVar *relation;     /* relation to update */
	PGList *targetList;       /* the target list (of PGResTarget) */
	PGNode *whereClause;      /* qualifications */
	PGList *fromClause;       /* optional from clause for more tables */
	PGList *returningList;    /* list of expressions to return */
	PGWithClause *withClause; /* WITH clause */
} PGUpdateStmt;

/* ----------------------
 *		Select Statement
 *
 * A "simple" SELECT is represented in the output of gram.y by a single
 * PGSelectStmt node; so is a VALUES construct.  A query containing set
 * operators (UNION, INTERSECT, EXCEPT) is represented by a tree of PGSelectStmt
 * nodes, in which the leaf nodes are component SELECTs and the internal nodes
 * represent UNION, INTERSECT, or EXCEPT operators.  Using the same node
 * type for both leaf and internal nodes allows gram.y to stick ORDER BY,
 * LIMIT, etc, clause values into a SELECT statement without worrying
 * whether it is a simple or compound SELECT.
 * ----------------------
 */
typedef enum PGSetOperation { PG_SETOP_NONE = 0, PG_SETOP_UNION, PG_SETOP_INTERSECT, PG_SETOP_EXCEPT } PGSetOperation;

typedef struct PGSelectStmt {
	PGNodeTag type;

	/*
	 * These fields are used only in "leaf" SelectStmts.
	 */
	PGList *distinctClause;   /* NULL, list of DISTINCT ON exprs, or
								 * lcons(NIL,NIL) for all (SELECT DISTINCT) */
	PGIntoClause *intoClause; /* target for SELECT INTO */
	PGList *targetList;       /* the target list (of PGResTarget) */
	PGList *fromClause;       /* the FROM clause */
	PGNode *whereClause;      /* WHERE qualification */
	PGList *groupClause;      /* GROUP BY clauses */
	PGNode *havingClause;     /* HAVING conditional-expression */
	PGList *windowClause;     /* WINDOW window_name AS (...), ... */
	PGNode *qualifyClause;    /* QUALIFY conditional-expression */

	/*
	 * In a "leaf" node representing a VALUES list, the above fields are all
	 * null, and instead this field is set.  Note that the elements of the
	 * sublists are just expressions, without PGResTarget decoration. Also note
	 * that a list element can be DEFAULT (represented as a PGSetToDefault
	 * node), regardless of the context of the VALUES list. It's up to parse
	 * analysis to reject that where not valid.
	 */
	PGList *valuesLists; /* untransformed list of expression lists */

	/*
	 * These fields are used in both "leaf" SelectStmts and upper-level
	 * SelectStmts.
	 */
	PGList *sortClause;       /* sort clause (a list of SortBy's) */
	PGNode *limitOffset;      /* # of result tuples to skip */
	PGNode *limitCount;       /* # of result tuples to return */
	PGNode *sampleOptions;    /* sample options (if any) */
	PGList *lockingClause;    /* FOR UPDATE (list of LockingClause's) */
	PGWithClause *withClause; /* WITH clause */

	/*
	 * These fields are used only in upper-level SelectStmts.
	 */
	PGSetOperation op;         /* type of set op */
	bool all;                  /* ALL specified? */
	struct PGSelectStmt *larg; /* left child */
	struct PGSelectStmt *rarg; /* right child */
	                           /* Eventually add fields for CORRESPONDING spec here */
} PGSelectStmt;

/* ----------------------
 *		Set Operation node for post-analysis query trees
 *
 * After parse analysis, a SELECT with set operations is represented by a
 * top-level PGQuery node containing the leaf SELECTs as subqueries in its
 * range table.  Its setOperations field shows the tree of set operations,
 * with leaf PGSelectStmt nodes replaced by PGRangeTblRef nodes, and internal
 * nodes replaced by SetOperationStmt nodes.  Information about the output
 * column types is added, too.  (Note that the child nodes do not necessarily
 * produce these types directly, but we've checked that their output types
 * can be coerced to the output column type.)  Also, if it's not UNION ALL,
 * information about the types' sort/group semantics is provided in the form
 * of a PGSortGroupClause list (same representation as, eg, DISTINCT).
 * The resolved common column collations are provided too; but note that if
 * it's not UNION ALL, it's okay for a column to not have a common collation,
 * so a member of the colCollations list could be InvalidOid even though the
 * column has a collatable type.
 * ----------------------
 */

/*****************************************************************************
 *		Other Statements (no optimizations required)
 *
 *		These are not touched by parser/analyze.c except to put them into
 *		the utilityStmt field of a Query.  This is eventually passed to
 *		ProcessUtility (by-passing rewriting and planning).  Some of the
 *		statements do need attention from parse analysis, and this is
 *		done by routines in parser/parse_utilcmd.c after ProcessUtility
 *		receives the command for execution.
 *		DECLARE CURSOR, EXPLAIN, and CREATE TABLE AS are special cases:
 *		they contain optimizable statements, which get processed normally
 *		by parser/analyze.c.
 *****************************************************************************/

/*
 * When a command can act on several kinds of objects with only one
 * parse structure required, use these constants to designate the
 * object type.  Note that commands typically don't support all the types.
 */

typedef enum PGObjectType {
	PG_OBJECT_ACCESS_METHOD,
	PG_OBJECT_AGGREGATE,
	PG_OBJECT_AMOP,
	PG_OBJECT_AMPROC,
	PG_OBJECT_ATTRIBUTE, /* type's attribute, when distinct from column */
	PG_OBJECT_CAST,
	PG_OBJECT_COLUMN,
	PG_OBJECT_COLLATION,
	PG_OBJECT_CONVERSION,
	PG_OBJECT_DATABASE,
	PG_OBJECT_DEFAULT,
	PG_OBJECT_DEFACL,
	PG_OBJECT_DOMAIN,
	PG_OBJECT_DOMCONSTRAINT,
	PG_OBJECT_EVENT_TRIGGER,
	PG_OBJECT_EXTENSION,
	PG_OBJECT_FDW,
	PG_OBJECT_FOREIGN_SERVER,
	PG_OBJECT_FOREIGN_TABLE,
	PG_OBJECT_FUNCTION,
	PG_OBJECT_TABLE_MACRO,
	PG_OBJECT_INDEX,
	PG_OBJECT_LANGUAGE,
	PG_OBJECT_LARGEOBJECT,
	PG_OBJECT_MATVIEW,
	PG_OBJECT_OPCLASS,
	PG_OBJECT_OPERATOR,
	PG_OBJECT_OPFAMILY,
	PG_OBJECT_POLICY,
	PG_OBJECT_PUBLICATION,
	PG_OBJECT_PUBLICATION_REL,
	PG_OBJECT_ROLE,
	PG_OBJECT_RULE,
	PG_OBJECT_SCHEMA,
	PG_OBJECT_SEQUENCE,
	PG_OBJECT_SUBSCRIPTION,
	PG_OBJECT_STATISTIC_EXT,
	PG_OBJECT_TABCONSTRAINT,
	PG_OBJECT_TABLE,
	PG_OBJECT_TABLESPACE,
	PG_OBJECT_TRANSFORM,
	PG_OBJECT_TRIGGER,
	PG_OBJECT_TSCONFIGURATION,
	PG_OBJECT_TSDICTIONARY,
	PG_OBJECT_TSPARSER,
	PG_OBJECT_TSTEMPLATE,
	PG_OBJECT_TYPE,
	PG_OBJECT_USER_MAPPING,
	PG_OBJECT_VIEW
} PGObjectType;

/* ----------------------
 *		Create Schema Statement
 *
 * NOTE: the schemaElts list contains raw parsetrees for component statements
 * of the schema, such as CREATE TABLE, GRANT, etc.  These are analyzed and
 * executed after the schema itself is created.
 * ----------------------
 */
typedef struct PGCreateSchemaStmt {
	PGNodeTag type;
	char *schemaname;                     /* the name of the schema to create */
	PGList *schemaElts;                   /* schema components (list of parsenodes) */
	PGOnCreateConflict onconflict;        /* what to do on create conflict */
} PGCreateSchemaStmt;

typedef enum PGDropBehavior {
	PG_DROP_RESTRICT, /* drop fails if any dependent objects */
	PG_DROP_CASCADE   /* remove dependent objects too */
} PGDropBehavior;

/* ----------------------
 *	Alter Table
 * ----------------------
 */
typedef struct PGAlterTableStmt {
	PGNodeTag type;
	PGRangeVar *relation; /* table to work on */
	PGList *cmds;         /* list of subcommands */
	PGObjectType relkind; /* type of object */
	bool missing_ok;      /* skip error if table missing */
} PGAlterTableStmt;

typedef enum PGAlterTableType {
	PG_AT_AddColumn,                 /* add column */
	PG_AT_AddColumnRecurse,          /* internal to commands/tablecmds.c */
	PG_AT_AddColumnToView,           /* implicitly via CREATE OR REPLACE VIEW */
	PG_AT_ColumnDefault,             /* alter column default */
	PG_AT_DropNotNull,               /* alter column drop not null */
	PG_AT_SetNotNull,                /* alter column set not null */
	PG_AT_SetStatistics,             /* alter column set statistics */
	PG_AT_SetOptions,                /* alter column set ( options ) */
	PG_AT_ResetOptions,              /* alter column reset ( options ) */
	PG_AT_SetStorage,                /* alter column set storage */
	PG_AT_DropColumn,                /* drop column */
	PG_AT_DropColumnRecurse,         /* internal to commands/tablecmds.c */
	PG_AT_AddIndex,                  /* add index */
	PG_AT_ReAddIndex,                /* internal to commands/tablecmds.c */
	PG_AT_AddConstraint,             /* add constraint */
	PG_AT_AddConstraintRecurse,      /* internal to commands/tablecmds.c */
	PG_AT_ReAddConstraint,           /* internal to commands/tablecmds.c */
	PG_AT_AlterConstraint,           /* alter constraint */
	PG_AT_ValidateConstraint,        /* validate constraint */
	PG_AT_ValidateConstraintRecurse, /* internal to commands/tablecmds.c */
	PG_AT_ProcessedConstraint,       /* pre-processed add constraint (local in
								 * parser/parse_utilcmd.c) */
	PG_AT_AddIndexConstraint,        /* add constraint using existing index */
	PG_AT_DropConstraint,            /* drop constraint */
	PG_AT_DropConstraintRecurse,     /* internal to commands/tablecmds.c */
	PG_AT_ReAddComment,              /* internal to commands/tablecmds.c */
	PG_AT_AlterColumnType,           /* alter column type */
	PG_AT_AlterColumnGenericOptions, /* alter column OPTIONS (...) */
	PG_AT_ChangeOwner,               /* change owner */
	PG_AT_ClusterOn,                 /* CLUSTER ON */
	PG_AT_DropCluster,               /* SET WITHOUT CLUSTER */
	PG_AT_SetLogged,                 /* SET LOGGED */
	PG_AT_SetUnLogged,               /* SET UNLOGGED */
	PG_AT_AddOids,                   /* SET WITH OIDS */
	PG_AT_AddOidsRecurse,            /* internal to commands/tablecmds.c */
	PG_AT_DropOids,                  /* SET WITHOUT OIDS */
	PG_AT_SetTableSpace,             /* SET TABLESPACE */
	PG_AT_SetRelOptions,             /* SET (...) -- AM specific parameters */
	PG_AT_ResetRelOptions,           /* RESET (...) -- AM specific parameters */
	PG_AT_ReplaceRelOptions,         /* replace reloption list in its entirety */
	PG_AT_EnableTrig,                /* ENABLE TRIGGER name */
	PG_AT_EnableAlwaysTrig,          /* ENABLE ALWAYS TRIGGER name */
	PG_AT_EnableReplicaTrig,         /* ENABLE REPLICA TRIGGER name */
	PG_AT_DisableTrig,               /* DISABLE TRIGGER name */
	PG_AT_EnableTrigAll,             /* ENABLE TRIGGER ALL */
	PG_AT_DisableTrigAll,            /* DISABLE TRIGGER ALL */
	PG_AT_EnableTrigUser,            /* ENABLE TRIGGER USER */
	PG_AT_DisableTrigUser,           /* DISABLE TRIGGER USER */
	PG_AT_EnableRule,                /* ENABLE RULE name */
	PG_AT_EnableAlwaysRule,          /* ENABLE ALWAYS RULE name */
	PG_AT_EnableReplicaRule,         /* ENABLE REPLICA RULE name */
	PG_AT_DisableRule,               /* DISABLE RULE name */
	PG_AT_AddInherit,                /* INHERIT parent */
	PG_AT_DropInherit,               /* NO INHERIT parent */
	PG_AT_AddOf,                     /* OF <type_name> */
	PG_AT_DropOf,                    /* NOT OF */
	PG_AT_ReplicaIdentity,           /* REPLICA IDENTITY */
	PG_AT_EnableRowSecurity,         /* ENABLE ROW SECURITY */
	PG_AT_DisableRowSecurity,        /* DISABLE ROW SECURITY */
	PG_AT_ForceRowSecurity,          /* FORCE ROW SECURITY */
	PG_AT_NoForceRowSecurity,        /* NO FORCE ROW SECURITY */
	PG_AT_GenericOptions,            /* OPTIONS (...) */
	PG_AT_AttachPartition,           /* ATTACH PARTITION */
	PG_AT_DetachPartition,           /* DETACH PARTITION */
	PG_AT_AddIdentity,               /* ADD IDENTITY */
	PG_AT_SetIdentity,               /* SET identity column options */
	AT_DropIdentity                  /* DROP IDENTITY */
} PGAlterTableType;

typedef struct PGAlterTableCmd /* one subcommand of an ALTER TABLE */
{
	PGNodeTag type;
	PGAlterTableType subtype; /* Type of table alteration to apply */
	char *name;               /* column, constraint, or trigger to act on,
								 * or tablespace */
	PGNode *def;              /* definition of new column, index,
								 * constraint, or parent table */
	PGDropBehavior behavior;  /* RESTRICT or CASCADE for DROP cases */
	bool missing_ok;          /* skip error if missing? */
} PGAlterTableCmd;

/*
 * Note: PGObjectWithArgs carries only the types of the input parameters of the
 * function.  So it is sufficient to identify an existing function, but it
 * is not enough info to define a function nor to call it.
 */
typedef struct PGObjectWithArgs {
	PGNodeTag type;
	PGList *objname;       /* qualified name of function/operator */
	PGList *objargs;       /* list of Typename nodes */
	bool args_unspecified; /* argument list was omitted, so name must
									 * be unique (note that objargs == NIL
									 * means zero args) */
} PGObjectWithArgs;

/* ----------------------
 *		Copy Statement
 *
 * We support "COPY relation FROM file", "COPY relation TO file", and
 * "COPY (query) TO file".  In any given PGCopyStmt, exactly one of "relation"
 * and "query" must be non-NULL.
 * ----------------------
 */
typedef struct PGCopyStmt {
	PGNodeTag type;
	PGRangeVar *relation; /* the relation to copy */
	PGNode *query;        /* the query (SELECT or DML statement with
								 * RETURNING) to copy, as a raw parse tree */
	PGList *attlist;      /* PGList of column names (as Strings), or NIL
								 * for all columns */
	bool is_from;         /* TO or FROM */
	bool is_program;      /* is 'filename' a program to popen? */
	char *filename;       /* filename, or NULL for STDIN/STDOUT */
	PGList *options;      /* PGList of PGDefElem nodes */
} PGCopyStmt;

/* ----------------------
 * SET Statement (includes RESET)
 *
 * "SET var TO DEFAULT" and "RESET var" are semantically equivalent, but we
 * preserve the distinction in VariableSetKind for CreateCommandTag().
 * ----------------------
 */
typedef enum {
	VAR_SET_VALUE,   /* SET var = value */
	VAR_SET_DEFAULT, /* SET var TO DEFAULT */
	VAR_SET_CURRENT, /* SET var FROM CURRENT */
	VAR_SET_MULTI,   /* special case for SET TRANSACTION ... */
	VAR_RESET,       /* RESET var */
	VAR_RESET_ALL    /* RESET ALL */
} VariableSetKind;

typedef enum {
	VAR_SET_SCOPE_LOCAL,   /* SET LOCAL var */
	VAR_SET_SCOPE_SESSION, /* SET SESSION var */
	VAR_SET_SCOPE_GLOBAL,  /* SET GLOBAL var */
	VAR_SET_SCOPE_DEFAULT  /* SET var (same as SET_SESSION) */
} VariableSetScope;

typedef struct PGVariableSetStmt {
	PGNodeTag type;
	VariableSetKind kind;
	VariableSetScope scope;
	char *name;    /* variable to be set */
	PGList *args;  /* PGList of PGAConst nodes */
} PGVariableSetStmt;

/* ----------------------
 * Show Statement
 * ----------------------
 */
typedef struct PGVariableShowStmt {
	PGNodeTag   type;
	char       *name;
	int         is_summary; // whether or not this is a DESCRIBE or a SUMMARIZE
} PGVariableShowStmt;

/* ----------------------
 * Show Statement with Select Statement
 * ----------------------
 */
typedef struct PGVariableShowSelectStmt
{
	PGNodeTag   type;
	PGNode     *stmt;
	char       *name;
	int         is_summary; // whether or not this is a DESCRIBE or a SUMMARIZE
} PGVariableShowSelectStmt;


/* ----------------------
 *		Create Table Statement
 *
 * NOTE: in the raw gram.y output, PGColumnDef and PGConstraint nodes are
 * intermixed in tableElts, and constraints is NIL.  After parse analysis,
 * tableElts contains just ColumnDefs, and constraints contains just
 * PGConstraint nodes (in fact, only PG_CONSTR_CHECK nodes, in the present
 * implementation).
 * ----------------------
 */

typedef struct PGCreateStmt {
	PGNodeTag type;
	PGRangeVar *relation;                 /* relation to create */
	PGList *tableElts;                    /* column definitions (list of PGColumnDef) */
	PGList *inhRelations;                 /* relations to inherit from (list of
										* inhRelation) */
	PGTypeName *ofTypename;               /* OF typename */
	PGList *constraints;                  /* constraints (list of PGConstraint nodes) */
	PGList *options;                      /* options from WITH clause */
	PGOnCommitAction oncommit;            /* what do we do at COMMIT? */
	char *tablespacename;                 /* table space to use, or NULL */
	PGOnCreateConflict onconflict;        /* what to do on create conflict */
} PGCreateStmt;

/* ----------
 * Definitions for constraints in PGCreateStmt
 *
 * Note that column defaults are treated as a type of constraint,
 * even though that's a bit odd semantically.
 *
 * For constraints that use expressions (CONSTR_CHECK, PG_CONSTR_DEFAULT)
 * we may have the expression in either "raw" form (an untransformed
 * parse tree) or "cooked" form (the nodeToString representation of
 * an executable expression tree), depending on how this PGConstraint
 * node was created (by parsing, or by inheritance from an existing
 * relation).  We should never have both in the same node!
 *
 * PG_FKCONSTR_ACTION_xxx values are stored into pg_constraint.confupdtype
 * and pg_constraint.confdeltype columns; PG_FKCONSTR_MATCH_xxx values are
 * stored into pg_constraint.confmatchtype.  Changing the code values may
 * require an initdb!
 *
 * If skip_validation is true then we skip checking that the existing rows
 * in the table satisfy the constraint, and just install the catalog entries
 * for the constraint.  A new FK constraint is marked as valid iff
 * initially_valid is true.  (Usually skip_validation and initially_valid
 * are inverses, but we can set both true if the table is known empty.)
 *
 * PGConstraint attributes (DEFERRABLE etc) are initially represented as
 * separate PGConstraint nodes for simplicity of parsing.  parse_utilcmd.c makes
 * a pass through the constraints list to insert the info into the appropriate
 * PGConstraint node.
 * ----------
 */

typedef enum PGConstrType /* types of constraints */
{ PG_CONSTR_NULL,         /* not standard SQL, but a lot of people
								 * expect it */
  PG_CONSTR_NOTNULL,
  PG_CONSTR_DEFAULT,
  PG_CONSTR_IDENTITY,
  PG_CONSTR_CHECK,
  PG_CONSTR_PRIMARY,
  PG_CONSTR_UNIQUE,
  PG_CONSTR_EXCLUSION,
  PG_CONSTR_FOREIGN,
  PG_CONSTR_ATTR_DEFERRABLE, /* attributes for previous constraint node */
  PG_CONSTR_ATTR_NOT_DEFERRABLE,
  PG_CONSTR_ATTR_DEFERRED,
  PG_CONSTR_ATTR_IMMEDIATE,
  PG_CONSTR_COMPRESSION,
  PG_CONSTR_GENERATED_VIRTUAL,
  PG_CONSTR_GENERATED_STORED,
  } PGConstrType;

/* Foreign key action codes */
#define PG_FKCONSTR_ACTION_NOACTION 'a'
#define PG_FKCONSTR_ACTION_RESTRICT 'r'
#define PG_FKCONSTR_ACTION_CASCADE 'c'
#define PG_FKCONSTR_ACTION_SETNULL 'n'
#define PG_FKCONSTR_ACTION_SETDEFAULT 'd'

/* Foreign key matchtype codes */
#define PG_FKCONSTR_MATCH_FULL 'f'
#define PG_FKCONSTR_MATCH_PARTIAL 'p'
#define PG_FKCONSTR_MATCH_SIMPLE 's'

typedef struct PGConstraint {
	PGNodeTag type;
	PGConstrType contype; /* see above */

	/* Fields used for most/all constraint types: */
	char *conname;     /* PGConstraint name, or NULL if unnamed */
	bool deferrable;   /* DEFERRABLE? */
	bool initdeferred; /* INITIALLY DEFERRED? */
	int location;      /* token location, or -1 if unknown */

	/* Fields used for constraints with expressions (CHECK and DEFAULT): */
	bool is_no_inherit; /* is constraint non-inheritable? */
	PGNode *raw_expr;   /* expr, as untransformed parse tree */
	char *cooked_expr;  /* expr, as nodeToString representation */
	char generated_when;

	/* Fields used for unique constraints (UNIQUE and PRIMARY KEY): */
	PGList *keys; /* String nodes naming referenced column(s) */

	/* Fields used for EXCLUSION constraints: */
	PGList *exclusions; /* list of (PGIndexElem, operator name) pairs */

	/* Fields used for index constraints (UNIQUE, PRIMARY KEY, EXCLUSION): */
	PGList *options;  /* options from WITH clause */
	char *indexname;  /* existing index to use; otherwise NULL */
	char *indexspace; /* index tablespace; NULL for default */
	/* These could be, but currently are not, used for UNIQUE/PKEY: */
	char *access_method;  /* index access method; NULL for default */
	PGNode *where_clause; /* partial index predicate */

	/* Fields used for FOREIGN KEY constraints: */
	PGRangeVar *pktable;   /* Primary key table */
	PGList *fk_attrs;      /* Attributes of foreign key */
	PGList *pk_attrs;      /* Corresponding attrs in PK table */
	char fk_matchtype;     /* FULL, PARTIAL, SIMPLE */
	char fk_upd_action;    /* ON UPDATE action */
	char fk_del_action;    /* ON DELETE action */
	PGList *old_conpfeqop; /* pg_constraint.conpfeqop of my former self */
	PGOid old_pktable_oid; /* pg_constraint.confrelid of my former
									 * self */

	/* Fields used for constraints that allow a NOT VALID specification */
	bool skip_validation; /* skip validation of existing rows? */
	bool initially_valid; /* mark the new constraint as valid? */


	/* Field Used for COMPRESSION constraint */
	char *compression_name;  /* existing index to use; otherwise NULL */

} PGConstraint;

/* ----------------------
 *		{Create|Alter} SEQUENCE Statement
 * ----------------------
 */

typedef struct PGCreateSeqStmt {
	PGNodeTag type;
	PGRangeVar *sequence; /* the sequence to create */
	PGList *options;
	PGOid ownerId; /* ID of owner, or InvalidOid for default */
	bool for_identity;
	PGOnCreateConflict onconflict;        /* what to do on create conflict */
} PGCreateSeqStmt;

typedef struct PGAlterSeqStmt {
	PGNodeTag type;
	PGRangeVar *sequence; /* the sequence to alter */
	PGList *options;
	bool for_identity;
	bool missing_ok; /* skip error if a role is missing? */
} PGAlterSeqStmt;

/* ----------------------
 *		CREATE FUNCTION Statement
 * ----------------------
 */

typedef struct PGCreateFunctionStmt {
	PGNodeTag type;
	PGRangeVar *name;
	PGList *params;
	PGNode *function;
  	PGNode *query;
	char relpersistence;
} PGCreateFunctionStmt;

/* ----------------------
 *		Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement
 * ----------------------
 */

typedef struct PGDropStmt {
	PGNodeTag type;
	PGList *objects;         /* list of names */
	PGObjectType removeType; /* object type */
	PGDropBehavior behavior; /* RESTRICT or CASCADE behavior */
	bool missing_ok;         /* skip error if object is missing? */
	bool concurrent;         /* drop index concurrently? */
} PGDropStmt;

/* ----------------------
 *		Create PGIndex Statement
 *
 * This represents creation of an index and/or an associated constraint.
 * If isconstraint is true, we should create a pg_constraint entry along
 * with the index.  But if indexOid isn't InvalidOid, we are not creating an
 * index, just a UNIQUE/PKEY constraint using an existing index.  isconstraint
 * must always be true in this case, and the fields describing the index
 * properties are empty.
 * ----------------------
 */
typedef struct PGIndexStmt {
	PGNodeTag type;
	char *idxname;          /* name of new index, or NULL for default */
	PGRangeVar *relation;   /* relation to build index on */
	char *accessMethod;     /* name of access method (eg. btree) */
	char *tableSpace;       /* tablespace, or NULL for default */
	PGList *indexParams;    /* columns to index: a list of PGIndexElem */
	PGList *options;        /* WITH clause options: a list of PGDefElem */
	PGNode *whereClause;    /* qualification (partial-index predicate) */
	PGList *excludeOpNames; /* exclusion operator names, or NIL if none */
	char *idxcomment;       /* comment to apply to index, or NULL */
	PGOid indexOid;         /* OID of an existing index, if any */
	PGOid oldNode;          /* relfilenode of existing storage, if any */
	bool unique;            /* is index unique? */
	bool primary;           /* is index a primary key? */
	bool isconstraint;      /* is it for a pkey/unique constraint? */
	bool deferrable;        /* is the constraint DEFERRABLE? */
	bool initdeferred;      /* is the constraint INITIALLY DEFERRED? */
	bool transformed;       /* true when transformIndexStmt is finished */
	bool concurrent;        /* should this be a concurrent index build? */
	PGOnCreateConflict onconflict;        /* what to do on create conflict */
} PGIndexStmt;

/* ----------------------
 *		Alter Object Rename Statement
 * ----------------------
 */
typedef struct PGRenameStmt {
	PGNodeTag type;
	PGObjectType renameType;   /* PG_OBJECT_TABLE, PG_OBJECT_COLUMN, etc */
	PGObjectType relationType; /* if column name, associated relation type */
	PGRangeVar *relation;      /* in case it's a table */
	PGNode *object;            /* in case it's some other object */
	char *subname;             /* name of contained object (column, rule,
								 * trigger, etc) */
	char *newname;             /* the new name */
	PGDropBehavior behavior;   /* RESTRICT or CASCADE behavior */
	bool missing_ok;           /* skip error if missing? */
} PGRenameStmt;

/* ----------------------
 *		ALTER object SET SCHEMA Statement
 * ----------------------
 */
typedef struct PGAlterObjectSchemaStmt {
	PGNodeTag type;
	PGObjectType objectType; /* PG_OBJECT_TABLE, PG_OBJECT_TYPE, etc */
	PGRangeVar *relation;    /* in case it's a table */
	PGNode *object;          /* in case it's some other object */
	char *newschema;         /* the new schema */
	bool missing_ok;         /* skip error if missing? */
} PGAlterObjectSchemaStmt;

/* ----------------------
 *		{Begin|Commit|Rollback} Transaction Statement
 * ----------------------
 */
typedef enum PGTransactionStmtKind {
	PG_TRANS_STMT_BEGIN,
	PG_TRANS_STMT_START, /* semantically identical to BEGIN */
	PG_TRANS_STMT_COMMIT,
	PG_TRANS_STMT_ROLLBACK,
	PG_TRANS_STMT_SAVEPOINT,
	PG_TRANS_STMT_RELEASE,
	PG_TRANS_STMT_ROLLBACK_TO,
	PG_TRANS_STMT_PREPARE,
	PG_TRANS_STMT_COMMIT_PREPARED,
	TRANS_STMT_ROLLBACK_PREPARED
} PGTransactionStmtKind;

typedef struct PGTransactionStmt {
	PGNodeTag type;
	PGTransactionStmtKind kind; /* see above */
	PGList *options;            /* for BEGIN/START and savepoint commands */
	char *gid;                  /* for two-phase-commit related commands */
} PGTransactionStmt;

/* ----------------------
 *		Create View Statement
 * ----------------------
 */
typedef enum PGViewCheckOption { PG_NO_CHECK_OPTION, PG_LOCAL_CHECK_OPTION, CASCADED_CHECK_OPTION } PGViewCheckOption;

typedef struct PGViewStmt {
	PGNodeTag type;
	PGRangeVar *view;                  /* the view to be created */
	PGList *aliases;                   /* target column names */
	PGNode *query;                     /* the SELECT query (as a raw parse tree) */
	PGOnCreateConflict onconflict;     /* what to do on create conflict */
	PGList *options;                   /* options from WITH clause */
	PGViewCheckOption withCheckOption; /* WITH CHECK OPTION */
} PGViewStmt;

/* ----------------------
 *		Load Statement
 * ----------------------
 */

typedef enum PGLoadInstallType { PG_LOAD_TYPE_LOAD,  PG_LOAD_TYPE_INSTALL, PG_LOAD_TYPE_FORCE_INSTALL } PGLoadInstallType;


typedef struct PGLoadStmt {
	PGNodeTag type;
	const char *filename; /* file to load */
	PGLoadInstallType load_type;
} PGLoadStmt;

/* ----------------------
 *		Vacuum and Analyze Statements
 *
 * Even though these are nominally two statements, it's convenient to use
 * just one node type for both.  Note that at least one of PG_VACOPT_VACUUM
 * and PG_VACOPT_ANALYZE must be set in options.
 * ----------------------
 */
typedef enum PGVacuumOption {
	PG_VACOPT_VACUUM = 1 << 0,               /* do VACUUM */
	PG_VACOPT_ANALYZE = 1 << 1,              /* do ANALYZE */
	PG_VACOPT_VERBOSE = 1 << 2,              /* print progress info */
	PG_VACOPT_FREEZE = 1 << 3,               /* FREEZE option */
	PG_VACOPT_FULL = 1 << 4,                 /* FULL (non-concurrent) vacuum */
	PG_VACOPT_NOWAIT = 1 << 5,               /* don't wait to get lock (autovacuum only) */
	PG_VACOPT_SKIPTOAST = 1 << 6,            /* don't process the TOAST table, if any */
	PG_VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */
} PGVacuumOption;

typedef struct PGVacuumStmt {
	PGNodeTag type;
	int options;          /* OR of PGVacuumOption flags */
	PGRangeVar *relation; /* single table to process, or NULL */
	PGList *va_cols;      /* list of column names, or NIL for all */
} PGVacuumStmt;

/* ----------------------
 *		Explain Statement
 *
 * The "query" field is initially a raw parse tree, and is converted to a
 * PGQuery node during parse analysis.  Note that rewriting and planning
 * of the query are always postponed until execution.
 * ----------------------
 */
typedef struct PGExplainStmt {
	PGNodeTag type;
	PGNode *query;   /* the query (see comments above) */
	PGList *options; /* list of PGDefElem nodes */
} PGExplainStmt;

/* ----------------------
 *		CREATE TABLE AS Statement (a/k/a SELECT INTO)
 *
 * A query written as CREATE TABLE AS will produce this node type natively.
 * A query written as SELECT ... INTO will be transformed to this form during
 * parse analysis.
 * A query written as CREATE MATERIALIZED view will produce this node type,
 * during parse analysis, since it needs all the same data.
 *
 * The "query" field is handled similarly to EXPLAIN, though note that it
 * can be a SELECT or an EXECUTE, but not other DML statements.
 * ----------------------
 */
typedef struct PGCreateTableAsStmt {
	PGNodeTag type;
	PGNode *query;        /* the query (see comments above) */
	PGIntoClause *into;   /* destination table */
	PGObjectType relkind; /* PG_OBJECT_TABLE or PG_OBJECT_MATVIEW */
	bool is_select_into;  /* it was written as SELECT INTO */
	PGOnCreateConflict onconflict;        /* what to do on create conflict */
} PGCreateTableAsStmt;

/* ----------------------
 * Checkpoint Statement
 * ----------------------
 */
typedef struct PGCheckPointStmt {
	PGNodeTag type;
	bool force;
} PGCheckPointStmt;

/* ----------------------
 *		PREPARE Statement
 * ----------------------
 */
typedef struct PGPrepareStmt {
	PGNodeTag type;
	char *name;       /* Name of plan, arbitrary */
	PGList *argtypes; /* Types of parameters (PGList of PGTypeName) */
	PGNode *query;    /* The query itself (as a raw parsetree) */
} PGPrepareStmt;

/* ----------------------
 *		EXECUTE Statement
 * ----------------------
 */

typedef struct PGExecuteStmt {
	PGNodeTag type;
	char *name;     /* The name of the plan to execute */
	PGList *params; /* Values to assign to parameters */
} PGExecuteStmt;

/* ----------------------
 *		DEALLOCATE Statement
 * ----------------------
 */
typedef struct PGDeallocateStmt {
	PGNodeTag type;
	char *name; /* The name of the plan to remove */
	            /* NULL means DEALLOCATE ALL */
} PGDeallocateStmt;

/* ----------------------
 * PRAGMA statements
 * Three types of pragma statements:
 * PRAGMA pragma_name;          (NOTHING)
 * PRAGMA pragma_name='param';  (ASSIGNMENT)
 * PRAGMA pragma_name('param'); (CALL)
 * ----------------------
 */
typedef enum { PG_PRAGMA_TYPE_NOTHING, PG_PRAGMA_TYPE_ASSIGNMENT, PG_PRAGMA_TYPE_CALL } PGPragmaKind;

typedef struct PGPragmaStmt {
	PGNodeTag type;
	PGPragmaKind kind;
	char *name;   /* variable to be set */
	PGList *args; /* PGList of PGAConst nodes */
} PGPragmaStmt;

/* ----------------------
 *		CALL Statement
 * ----------------------
 */

typedef struct PGCallStmt {
	PGNodeTag type;
	PGNode *func;
} PGCallStmt;

/* ----------------------
 *		EXPORT/IMPORT Statements
 * ----------------------
 */

typedef struct PGExportStmt {
	PGNodeTag type;
	char *filename;       /* filename */
	PGList *options;      /* PGList of PGDefElem nodes */
} PGExportStmt;

typedef struct PGImportStmt {
	PGNodeTag type;
	char *filename;       /* filename */
} PGImportStmt;

/* ----------------------
 *		Interval Constant
 * ----------------------
 */
typedef struct PGIntervalConstant {
	PGNodeTag type;
	int val_type;         /* interval constant type, either duckdb_libpgquery::T_PGString, duckdb_libpgquery::T_PGInteger or duckdb_libpgquery::T_PGAExpr */
	char *sval;           /* duckdb_libpgquery::T_PGString */
	int ival;             /* duckdb_libpgquery::T_PGString */
	PGNode *eval;         /* duckdb_libpgquery::T_PGAExpr */
	PGList *typmods;      /* how to interpret the interval constant (year, month, day, etc)  */
	int location;         /* token location, or -1 if unknown */
} PGIntervalConstant;

/* ----------------------
 *		Sample Options
 * ----------------------
 */
typedef struct PGSampleSize {
	PGNodeTag type;
	bool is_percentage;   /* whether or not the sample size is expressed in row numbers or a percentage */
	PGValue sample_size;  /* sample size */
} PGSampleSize;

typedef struct PGSampleOptions {
	PGNodeTag type;
	PGNode *sample_size;      /* the size of the sample to take */
	char *method;             /* sample method, or NULL for default */
	int seed;                 /* seed, or NULL for default; */
	int location;             /* token location, or -1 if unknown */
} PGSampleOptions;

/* ----------------------
 *      Limit Percentage
 * ----------------------
 */
typedef struct PGLimitPercent {
	PGNodeTag type;
    PGNode* limit_percent;  /* limit percent */
} PGLimitPercent;

/* ----------------------
 *		Lambda Function (or Arrow Operator)
 * ----------------------
 */
typedef struct PGLambdaFunction {
	PGNodeTag type;
	PGNode *lhs;                 /* list of input parameters */
	PGNode *rhs;                 /* lambda expression */
	int location;                /* token location, or -1 if unknown */
} PGLambdaFunction;

/* ----------------------
 *		Positional Reference
 * ----------------------
 */
typedef struct PGPositionalReference {
	PGNodeTag type;
	int position;
	int location;                /* token location, or -1 if unknown */
} PGPositionalReference;

/* ----------------------
 *		Type Statement
 * ----------------------
 */

typedef enum { PG_NEWTYPE_NONE, PG_NEWTYPE_ENUM, PG_NEWTYPE_ALIAS } PGNewTypeKind;

typedef struct PGCreateTypeStmt
{
	PGNodeTag		type;
	PGNewTypeKind	kind;
	PGList	   *typeName;		/* qualified name (list of Value strings) */
	PGList	   *vals;			/* enum values (list of Value strings) */
	PGTypeName *ofType;			/* original type of alias name */
} PGCreateTypeStmt;





}


// LICENSE_CHANGE_END


namespace duckdb {

class ColumnDefinition;
class StackChecker;
struct OrderByNode;
struct CopyInfo;
struct CommonTableExpressionInfo;
struct GroupingExpressionMap;

//! The transformer class is responsible for transforming the internal Postgres
//! parser representation into the DuckDB representation
class Transformer {
	friend class StackChecker;

public:
	explicit Transformer(idx_t max_expression_depth_p);
	explicit Transformer(Transformer *parent);

	//! Transforms a Postgres parse tree into a set of SQL Statements
	bool TransformParseTree(duckdb_libpgquery::PGList *tree, vector<unique_ptr<SQLStatement>> &statements);
	string NodetypeToString(duckdb_libpgquery::PGNodeTag type);

	idx_t ParamCount() {
		return parent ? parent->ParamCount() : prepared_statement_parameter_index;
	}

private:
	Transformer *parent;
	idx_t max_expression_depth;
	//! The current prepared statement parameter index
	idx_t prepared_statement_parameter_index = 0;
	//! Holds window expressions defined by name. We need those when transforming the expressions referring to them.
	unordered_map<string, duckdb_libpgquery::PGWindowDef *> window_clauses;

	void SetParamCount(idx_t new_count) {
		if (parent) {
			parent->SetParamCount(new_count);
		} else {
			this->prepared_statement_parameter_index = new_count;
		}
	}

private:
	//! Transforms a Postgres statement into a single SQL statement
	unique_ptr<SQLStatement> TransformStatement(duckdb_libpgquery::PGNode *stmt);
	//! Transforms a Postgres statement into a single SQL statement
	unique_ptr<SQLStatement> TransformStatementInternal(duckdb_libpgquery::PGNode *stmt);
	//===--------------------------------------------------------------------===//
	// Statement transformation
	//===--------------------------------------------------------------------===//
	//! Transform a Postgres duckdb_libpgquery::T_PGSelectStmt node into a SelectStatement
	unique_ptr<SelectStatement> TransformSelect(duckdb_libpgquery::PGNode *node, bool isSelect = true);
	//! Transform a Postgres T_AlterStmt node into a AlterStatement
	unique_ptr<AlterStatement> TransformAlter(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGRenameStmt node into a RenameStatement
	unique_ptr<AlterStatement> TransformRename(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGCreateStmt node into a CreateStatement
	unique_ptr<CreateStatement> TransformCreateTable(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGCreateStmt node into a CreateStatement
	unique_ptr<CreateStatement> TransformCreateTableAs(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres node into a CreateStatement
	unique_ptr<CreateStatement> TransformCreateSchema(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGCreateSeqStmt node into a CreateStatement
	unique_ptr<CreateStatement> TransformCreateSequence(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGViewStmt node into a CreateStatement
	unique_ptr<CreateStatement> TransformCreateView(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGIndexStmt node into CreateStatement
	unique_ptr<CreateStatement> TransformCreateIndex(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGCreateFunctionStmt node into CreateStatement
	unique_ptr<CreateStatement> TransformCreateFunction(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGCreateTypeStmt node into CreateStatement
	unique_ptr<CreateStatement> TransformCreateType(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGAlterSeqStmt node into CreateStatement
	unique_ptr<AlterStatement> TransformAlterSequence(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGDropStmt node into a Drop[Table,Schema]Statement
	unique_ptr<SQLStatement> TransformDrop(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGInsertStmt node into a InsertStatement
	unique_ptr<InsertStatement> TransformInsert(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGCopyStmt node into a CopyStatement
	unique_ptr<CopyStatement> TransformCopy(duckdb_libpgquery::PGNode *node);
	void TransformCopyOptions(CopyInfo &info, duckdb_libpgquery::PGList *options);
	//! Transform a Postgres duckdb_libpgquery::T_PGTransactionStmt node into a TransactionStatement
	unique_ptr<TransactionStatement> TransformTransaction(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres T_DeleteStatement node into a DeleteStatement
	unique_ptr<DeleteStatement> TransformDelete(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGUpdateStmt node into a UpdateStatement
	unique_ptr<UpdateStatement> TransformUpdate(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGPragmaStmt node into a PragmaStatement
	unique_ptr<SQLStatement> TransformPragma(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGExportStmt node into a ExportStatement
	unique_ptr<ExportStatement> TransformExport(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres duckdb_libpgquery::T_PGImportStmt node into a PragmaStatement
	unique_ptr<PragmaStatement> TransformImport(duckdb_libpgquery::PGNode *node);
	unique_ptr<ExplainStatement> TransformExplain(duckdb_libpgquery::PGNode *node);
	unique_ptr<VacuumStatement> TransformVacuum(duckdb_libpgquery::PGNode *node);
	unique_ptr<SQLStatement> TransformShow(duckdb_libpgquery::PGNode *node);
	unique_ptr<ShowStatement> TransformShowSelect(duckdb_libpgquery::PGNode *node);

	unique_ptr<PrepareStatement> TransformPrepare(duckdb_libpgquery::PGNode *node);
	unique_ptr<ExecuteStatement> TransformExecute(duckdb_libpgquery::PGNode *node);
	unique_ptr<CallStatement> TransformCall(duckdb_libpgquery::PGNode *node);
	unique_ptr<DropStatement> TransformDeallocate(duckdb_libpgquery::PGNode *node);
	unique_ptr<SetStatement> TransformSet(duckdb_libpgquery::PGNode *node);
	unique_ptr<SQLStatement> TransformCheckpoint(duckdb_libpgquery::PGNode *node);
	unique_ptr<LoadStatement> TransformLoad(duckdb_libpgquery::PGNode *node);

	//===--------------------------------------------------------------------===//
	// Query Node Transform
	//===--------------------------------------------------------------------===//
	//! Transform a Postgres duckdb_libpgquery::T_PGSelectStmt node into a QueryNode
	unique_ptr<QueryNode> TransformSelectNode(duckdb_libpgquery::PGSelectStmt *node);

	//===--------------------------------------------------------------------===//
	// Expression Transform
	//===--------------------------------------------------------------------===//
	//! Transform a Postgres boolean expression into an Expression
	unique_ptr<ParsedExpression> TransformBoolExpr(duckdb_libpgquery::PGBoolExpr *root);
	//! Transform a Postgres case expression into an Expression
	unique_ptr<ParsedExpression> TransformCase(duckdb_libpgquery::PGCaseExpr *root);
	//! Transform a Postgres type cast into an Expression
	unique_ptr<ParsedExpression> TransformTypeCast(duckdb_libpgquery::PGTypeCast *root);
	//! Transform a Postgres coalesce into an Expression
	unique_ptr<ParsedExpression> TransformCoalesce(duckdb_libpgquery::PGAExpr *root);
	//! Transform a Postgres column reference into an Expression
	unique_ptr<ParsedExpression> TransformColumnRef(duckdb_libpgquery::PGColumnRef *root);
	//! Transform a Postgres constant value into an Expression
	unique_ptr<ConstantExpression> TransformValue(duckdb_libpgquery::PGValue val);
	//! Transform a Postgres operator into an Expression
	unique_ptr<ParsedExpression> TransformAExpr(duckdb_libpgquery::PGAExpr *root);
	unique_ptr<ParsedExpression> TransformAExprInternal(duckdb_libpgquery::PGAExpr *root);
	//! Transform a Postgres abstract expression into an Expression
	unique_ptr<ParsedExpression> TransformExpression(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres function call into an Expression
	unique_ptr<ParsedExpression> TransformFuncCall(duckdb_libpgquery::PGFuncCall *root);
	//! Transform a Postgres boolean expression into an Expression
	unique_ptr<ParsedExpression> TransformInterval(duckdb_libpgquery::PGIntervalConstant *root);
	//! Transform a Postgres lambda node [e.g. (x, y) -> x + y] into a lambda expression
	unique_ptr<ParsedExpression> TransformLambda(duckdb_libpgquery::PGLambdaFunction *node);
	//! Transform a Postgres array access node (e.g. x[1] or x[1:3])
	unique_ptr<ParsedExpression> TransformArrayAccess(duckdb_libpgquery::PGAIndirection *node);
	//! Transform a positional reference (e.g. #1)
	unique_ptr<ParsedExpression> TransformPositionalReference(duckdb_libpgquery::PGPositionalReference *node);
	unique_ptr<ParsedExpression> TransformStarExpression(duckdb_libpgquery::PGNode *node);

	//! Transform a Postgres constant value into an Expression
	unique_ptr<ParsedExpression> TransformConstant(duckdb_libpgquery::PGAConst *c);
	unique_ptr<ParsedExpression> TransformGroupingFunction(duckdb_libpgquery::PGGroupingFunc *n);
	unique_ptr<ParsedExpression> TransformResTarget(duckdb_libpgquery::PGResTarget *root);
	unique_ptr<ParsedExpression> TransformNullTest(duckdb_libpgquery::PGNullTest *root);
	unique_ptr<ParsedExpression> TransformParamRef(duckdb_libpgquery::PGParamRef *node);
	unique_ptr<ParsedExpression> TransformNamedArg(duckdb_libpgquery::PGNamedArgExpr *root);

	unique_ptr<ParsedExpression> TransformSQLValueFunction(duckdb_libpgquery::PGSQLValueFunction *node);

	unique_ptr<ParsedExpression> TransformSubquery(duckdb_libpgquery::PGSubLink *root);
	//===--------------------------------------------------------------------===//
	// Constraints transform
	//===--------------------------------------------------------------------===//
	unique_ptr<Constraint> TransformConstraint(duckdb_libpgquery::PGListCell *cell);

	unique_ptr<Constraint> TransformConstraint(duckdb_libpgquery::PGListCell *cell, ColumnDefinition &column,
	                                           idx_t index);

	//===--------------------------------------------------------------------===//
	// Collation transform
	//===--------------------------------------------------------------------===//
	unique_ptr<ParsedExpression> TransformCollateExpr(duckdb_libpgquery::PGCollateClause *collate);

	string TransformCollation(duckdb_libpgquery::PGCollateClause *collate);

	ColumnDefinition TransformColumnDefinition(duckdb_libpgquery::PGColumnDef *cdef);
	//===--------------------------------------------------------------------===//
	// Helpers
	//===--------------------------------------------------------------------===//
	OnCreateConflict TransformOnConflict(duckdb_libpgquery::PGOnCreateConflict conflict);
	string TransformAlias(duckdb_libpgquery::PGAlias *root, vector<string> &column_name_alias);
	void TransformCTE(duckdb_libpgquery::PGWithClause *de_with_clause, CommonTableExpressionMap &cte_map);
	unique_ptr<SelectStatement> TransformRecursiveCTE(duckdb_libpgquery::PGCommonTableExpr *node,
	                                                  CommonTableExpressionInfo &info);

	unique_ptr<ParsedExpression> TransformUnaryOperator(const string &op, unique_ptr<ParsedExpression> child);
	unique_ptr<ParsedExpression> TransformBinaryOperator(const string &op, unique_ptr<ParsedExpression> left,
	                                                     unique_ptr<ParsedExpression> right);
	//===--------------------------------------------------------------------===//
	// TableRef transform
	//===--------------------------------------------------------------------===//
	//! Transform a Postgres node into a TableRef
	unique_ptr<TableRef> TransformTableRefNode(duckdb_libpgquery::PGNode *node);
	//! Transform a Postgres FROM clause into a TableRef
	unique_ptr<TableRef> TransformFrom(duckdb_libpgquery::PGList *root);
	//! Transform a Postgres table reference into a TableRef
	unique_ptr<TableRef> TransformRangeVar(duckdb_libpgquery::PGRangeVar *root);
	//! Transform a Postgres table-producing function into a TableRef
	unique_ptr<TableRef> TransformRangeFunction(duckdb_libpgquery::PGRangeFunction *root);
	//! Transform a Postgres join node into a TableRef
	unique_ptr<TableRef> TransformJoin(duckdb_libpgquery::PGJoinExpr *root);
	//! Transform a table producing subquery into a TableRef
	unique_ptr<TableRef> TransformRangeSubselect(duckdb_libpgquery::PGRangeSubselect *root);
	//! Transform a VALUES list into a set of expressions
	unique_ptr<TableRef> TransformValuesList(duckdb_libpgquery::PGList *list);

	//! Transform a range var into a (schema) qualified name
	QualifiedName TransformQualifiedName(duckdb_libpgquery::PGRangeVar *root);

	//! Transform a Postgres TypeName string into a LogicalType
	LogicalType TransformTypeName(duckdb_libpgquery::PGTypeName *name);

	//! Transform a Postgres GROUP BY expression into a list of Expression
	bool TransformGroupBy(duckdb_libpgquery::PGList *group, SelectNode &result);
	void TransformGroupByNode(duckdb_libpgquery::PGNode *n, GroupingExpressionMap &map, SelectNode &result,
	                          vector<GroupingSet> &result_sets);
	void AddGroupByExpression(unique_ptr<ParsedExpression> expression, GroupingExpressionMap &map, GroupByNode &result,
	                          vector<idx_t> &result_set);
	void TransformGroupByExpression(duckdb_libpgquery::PGNode *n, GroupingExpressionMap &map, GroupByNode &result,
	                                vector<idx_t> &result_set);
	//! Transform a Postgres ORDER BY expression into an OrderByDescription
	bool TransformOrderBy(duckdb_libpgquery::PGList *order, vector<OrderByNode> &result);

	//! Transform a Postgres SELECT clause into a list of Expressions
	void TransformExpressionList(duckdb_libpgquery::PGList &list, vector<unique_ptr<ParsedExpression>> &result);

	//! Transform a Postgres PARTITION BY/ORDER BY specification into lists of expressions
	void TransformWindowDef(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr);
	//! Transform a Postgres window frame specification into frame expressions
	void TransformWindowFrame(duckdb_libpgquery::PGWindowDef *window_spec, WindowExpression *expr);

	unique_ptr<SampleOptions> TransformSampleOptions(duckdb_libpgquery::PGNode *options);

private:
	//! Current stack depth
	idx_t stack_depth;

	void InitializeStackCheck();
	StackChecker StackCheck(idx_t extra_stack = 1);
};

class StackChecker {
public:
	StackChecker(Transformer &transformer, idx_t stack_usage);
	~StackChecker();
	StackChecker(StackChecker &&) noexcept;
	StackChecker(const StackChecker &) = delete;

private:
	Transformer &transformer;
	idx_t stack_usage;
};

vector<string> ReadPgListToString(duckdb_libpgquery::PGList *column_list);

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/extension_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class ExtensionStatement : public SQLStatement {
public:
	ExtensionStatement(ParserExtension extension, unique_ptr<ParserExtensionParseData> parse_data);

	//! The ParserExtension this statement was generated from
	ParserExtension extension;
	//! The parse data for this specific statement
	unique_ptr<ParserExtensionParseData> parse_data;

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

//===----------------------------------------------------------------------===//
//                         DuckDB
//
// postgres_parser.hpp
//
//
//===----------------------------------------------------------------------===//



#include <string>
#include <vector>



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list



#include <cstdint>
#include <string>

namespace duckdb_libpgquery {

enum class PGSimplifiedTokenType : uint8_t {
	PG_SIMPLIFIED_TOKEN_IDENTIFIER,
	PG_SIMPLIFIED_TOKEN_NUMERIC_CONSTANT,
	PG_SIMPLIFIED_TOKEN_STRING_CONSTANT,
	PG_SIMPLIFIED_TOKEN_OPERATOR,
	PG_SIMPLIFIED_TOKEN_KEYWORD,
	PG_SIMPLIFIED_TOKEN_COMMENT
};

struct PGSimplifiedToken {
	PGSimplifiedTokenType type;
	int32_t start;
};

enum class PGKeywordCategory : uint8_t {
	PG_KEYWORD_RESERVED,
	PG_KEYWORD_UNRESERVED,
	PG_KEYWORD_TYPE_FUNC,
	PG_KEYWORD_COL_NAME
};

struct PGKeyword {
	std::string text;
	PGKeywordCategory category;
};

}


// LICENSE_CHANGE_END


namespace duckdb {
class PostgresParser {
public:
	PostgresParser();
	~PostgresParser();

	bool success;
	duckdb_libpgquery::PGList *parse_tree;
	std::string error_message;
	int error_location;
public:
	void Parse(const std::string &query);
	static std::vector<duckdb_libpgquery::PGSimplifiedToken> Tokenize(const std::string &query);

	static bool IsKeyword(const std::string &text);
	static std::vector<duckdb_libpgquery::PGKeyword> KeywordList();

	static void SetPreserveIdentifierCase(bool downcase);
};

}


// LICENSE_CHANGE_END


// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #11
// See the end of this file for a list

/*-------------------------------------------------------------------------
 *
 * parser.h
 *		Definitions for the "raw" parser (flex and bison phases only)
 *
 * This is the external API for the raw lexing/parsing functions.
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development PGGroup
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/parser/parser.h
 *
 *-------------------------------------------------------------------------
 */




#include <vector>

namespace duckdb_libpgquery {

typedef enum PGBackslashQuoteType {
	PG_BACKSLASH_QUOTE_OFF,
	PG_BACKSLASH_QUOTE_ON,
	PG_BACKSLASH_QUOTE_SAFE_ENCODING
} PGBackslashQuoteType;

/* Primary entry point for the raw parsing functions */
PGList *raw_parser(const char *str);

bool is_keyword(const char *str);
std::vector<PGKeyword> keyword_list();

std::vector<PGSimplifiedToken> tokenize(const char *str);

/* Utility functions exported by gram.y (perhaps these should be elsewhere) */
PGList *SystemFuncName(const char *name);
PGTypeName *SystemTypeName(const char *name);

}

// LICENSE_CHANGE_END
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/alter_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class AlterStatement : public SQLStatement {
public:
	AlterStatement();

	unique_ptr<AlterInfo> info;

protected:
	AlterStatement(const AlterStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/call_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class CallStatement : public SQLStatement {
public:
	CallStatement();

	unique_ptr<ParsedExpression> function;

protected:
	CallStatement(const CallStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/execute_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class ExecuteStatement : public SQLStatement {
public:
	ExecuteStatement();

	string name;
	vector<unique_ptr<ParsedExpression>> values;

protected:
	ExecuteStatement(const ExecuteStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/export_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class ExportStatement : public SQLStatement {
public:
	explicit ExportStatement(unique_ptr<CopyInfo> info);

	unique_ptr<CopyInfo> info;

protected:
	ExportStatement(const ExportStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/load_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class LoadStatement : public SQLStatement {
public:
	LoadStatement();

protected:
	LoadStatement(const LoadStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;

	unique_ptr<LoadInfo> info;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/prepare_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class PrepareStatement : public SQLStatement {
public:
	PrepareStatement();

	unique_ptr<SQLStatement> statement;
	string name;

protected:
	PrepareStatement(const PrepareStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/set_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class SetStatement : public SQLStatement {
public:
	SetStatement(std::string name_p, Value value_p, SetScope scope_p);

protected:
	SetStatement(const SetStatement &other) = default;

public:
	unique_ptr<SQLStatement> Copy() const override;

	std::string name;
	Value value;
	SetScope scope;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/show_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class ShowStatement : public SQLStatement {
public:
	ShowStatement();

	unique_ptr<ShowSelectInfo> info;

protected:
	ShowStatement(const ShowStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/transaction_statement.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class TransactionStatement : public SQLStatement {
public:
	explicit TransactionStatement(TransactionType type);

	unique_ptr<TransactionInfo> info;

protected:
	TransactionStatement(const TransactionStatement &other);

public:
	unique_ptr<SQLStatement> Copy() const override;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/parser/statement/vacuum_statement.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

class VacuumStatement : public SQLStatement {
public:
	VacuumStatement();

	unique_ptr<VacuumInfo> info;

protected:
	VacuumStatement(const VacuumStatement &other) : SQLStatement(other) {};

public:
	unique_ptr<SQLStatement> Copy() const override;
};

} // namespace duckdb




















//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/aggregate_binder.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The AggregateBinder is responsible for binding aggregate statements extracted from a SELECT clause (by the
//! SelectBinder)
class AggregateBinder : public ExpressionBinder {
	friend class SelectBinder;

public:
	AggregateBinder(Binder &binder, ClientContext &context);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/select_binder.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
class BoundColumnRefExpression;
class WindowExpression;

class BoundSelectNode;

struct BoundGroupInformation {
	expression_map_t<idx_t> map;
	case_insensitive_map_t<idx_t> alias_map;
};

//! The SELECT binder is responsible for binding an expression within the SELECT clause of a SQL statement
class SelectBinder : public ExpressionBinder {
public:
	SelectBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info);

	bool BoundAggregates() {
		return bound_aggregate;
	}
	void ResetBindings() {
		this->bound_aggregate = false;
		this->bound_columns.clear();
	}

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	BindResult BindAggregate(FunctionExpression &expr, AggregateFunctionCatalogEntry *function, idx_t depth) override;

	BindResult BindUnnest(FunctionExpression &function, idx_t depth) override;

	bool inside_window;
	bool bound_aggregate = false;

	BoundSelectNode &node;
	BoundGroupInformation &info;

protected:
	BindResult BindGroupingFunction(OperatorExpression &op, idx_t depth) override;
	BindResult BindWindow(WindowExpression &expr, idx_t depth);

	idx_t TryBindGroup(ParsedExpression &expr, idx_t depth);
	BindResult BindGroup(ParsedExpression &expr, idx_t depth, idx_t group_index);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/query_node/bound_select_node.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;
};
} // namespace duckdb




namespace duckdb {

class BoundGroupByNode {
public:
	//! The total set of all group expressions
	vector<unique_ptr<Expression>> group_expressions;
	//! The different grouping sets as they map to the group expressions
	vector<GroupingSet> grouping_sets;
};

//! Bound equivalent of SelectNode
class BoundSelectNode : public BoundQueryNode {
public:
	BoundSelectNode() : BoundQueryNode(QueryNodeType::SELECT_NODE) {
	}

	//! The original unparsed expressions. This is exported after binding, because the binding might change the
	//! expressions (e.g. when a * clause is present)
	vector<unique_ptr<ParsedExpression>> original_expressions;

	//! The projection list
	vector<unique_ptr<Expression>> select_list;
	//! The FROM clause
	unique_ptr<BoundTableRef> from_table;
	//! The WHERE clause
	unique_ptr<Expression> where_clause;
	//! list of groups
	BoundGroupByNode groups;
	//! HAVING clause
	unique_ptr<Expression> having;
	//! QUALIFY clause
	unique_ptr<Expression> qualify;
	//! SAMPLE clause
	unique_ptr<SampleOptions> sample_options;

	//! The amount of columns in the final result
	idx_t column_count;

	//! Index used by the LogicalProjection
	idx_t projection_index;

	//! Group index used by the LogicalAggregate (only used if HasAggregation is true)
	idx_t group_index;
	//! Table index for the projection child of the group op
	idx_t group_projection_index;
	//! Aggregate index used by the LogicalAggregate (only used if HasAggregation is true)
	idx_t aggregate_index;
	//! Index used for GROUPINGS column references
	idx_t groupings_index;
	//! Aggregate functions to compute (only used if HasAggregation is true)
	vector<unique_ptr<Expression>> aggregates;

	//! GROUPING function calls
	vector<vector<idx_t>> grouping_functions;

	//! Map from aggregate function to aggregate index (used to eliminate duplicate aggregates)
	expression_map_t<idx_t> aggregate_map;

	//! Window index used by the LogicalWindow (only used if HasWindow is true)
	idx_t window_index;
	//! Window functions to compute (only used if HasWindow is true)
	vector<unique_ptr<Expression>> windows;

	idx_t unnest_index;
	//! Unnest expression
	vector<unique_ptr<Expression>> unnests;

	//! Index of pruned node
	idx_t prune_index;
	bool need_prune = false;

public:
	idx_t GetRootIndex() override {
		return need_prune ? prune_index : projection_index;
	}
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/where_binder.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class ColumnAliasBinder;

//! The WHERE binder is responsible for binding an expression within the WHERE clause of a SQL statement
class WhereBinder : public ExpressionBinder {
public:
	WhereBinder(Binder &binder, ClientContext &context, ColumnAliasBinder *column_alias_binder = nullptr);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	string UnsupportedAggregateMessage() override;

private:
	BindResult BindColumnRef(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth, bool root_expression);

	ColumnAliasBinder *column_alias_binder;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/query_node/bound_recursive_cte_node.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Bound equivalent of SetOperationNode
class BoundRecursiveCTENode : public BoundQueryNode {
public:
	BoundRecursiveCTENode() : BoundQueryNode(QueryNodeType::RECURSIVE_CTE_NODE) {
	}

	//! Keep track of the CTE name this node represents
	string ctename;

	bool union_all;
	//! The left side of the set operation
	unique_ptr<BoundQueryNode> left;
	//! The right side of the set operation
	unique_ptr<BoundQueryNode> right;

	//! Index used by the set operation
	idx_t setop_index;
	//! The binder used by the left side of the set operation
	shared_ptr<Binder> left_binder;
	//! The binder used by the right side of the set operation
	shared_ptr<Binder> right_binder;

public:
	idx_t GetRootIndex() override {
		return setop_index;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/column_alias_binder.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

class BoundSelectNode;
class ColumnRefExpression;

//! A helper binder for WhereBinder and HavingBinder which support alias as a columnref.
class ColumnAliasBinder {
public:
	ColumnAliasBinder(BoundSelectNode &node, const case_insensitive_map_t<idx_t> &alias_map);

	BindResult BindAlias(ExpressionBinder &enclosing_binder, ColumnRefExpression &expr, idx_t depth,
	                     bool root_expression);

private:
	BoundSelectNode &node;
	const case_insensitive_map_t<idx_t> &alias_map;
	bool in_alias;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/constant_binder.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The Constant binder can bind ONLY constant foldable expressions (i.e. no subqueries, column refs, etc)
class ConstantBinder : public ExpressionBinder {
public:
	ConstantBinder(Binder &binder, ClientContext &context, string clause);

	//! The location where this binder is used, used for error messages
	string clause;

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr, idx_t depth, bool root_expression = false) override;

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/group_binder.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class ConstantExpression;
class ColumnRefExpression;

//! The GROUP binder is responsible for binding expressions in the GROUP BY clause
class GroupBinder : public ExpressionBinder {
public:
	GroupBinder(Binder &binder, ClientContext &context, SelectNode &node, idx_t group_index,
	            case_insensitive_map_t<idx_t> &alias_map, case_insensitive_map_t<idx_t> &group_alias_map);

	//! The unbound root expression
	unique_ptr<ParsedExpression> unbound_expression;
	//! The group index currently being bound
	idx_t bind_index;

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth, bool root_expression) override;

	string UnsupportedAggregateMessage() override;

	BindResult BindSelectRef(idx_t entry);
	BindResult BindColumnRef(ColumnRefExpression &expr);
	BindResult BindConstant(ConstantExpression &expr);

	SelectNode &node;
	case_insensitive_map_t<idx_t> &alias_map;
	case_insensitive_map_t<idx_t> &group_alias_map;
	unordered_set<idx_t> used_aliases;

	idx_t group_index;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/having_binder.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! The HAVING binder is responsible for binding an expression within the HAVING clause of a SQL statement
class HavingBinder : public SelectBinder {
public:
	HavingBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info,
	             case_insensitive_map_t<idx_t> &alias_map);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

private:
	BindResult BindColumnRef(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth, bool root_expression);

	ColumnAliasBinder column_alias_binder;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/qualify_binder.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! The QUALIFY binder is responsible for binding an expression within the QUALIFY clause of a SQL statement
class QualifyBinder : public SelectBinder {
public:
	QualifyBinder(Binder &binder, ClientContext &context, BoundSelectNode &node, BoundGroupInformation &info,
	              case_insensitive_map_t<idx_t> &alias_map);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

private:
	BindResult BindColumnRef(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth, bool root_expression);

	ColumnAliasBinder column_alias_binder;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/order_binder.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
class Binder;
class Expression;
class SelectNode;

//! The ORDER binder is responsible for binding an expression within the ORDER BY clause of a SQL statement
class OrderBinder {
public:
	OrderBinder(vector<Binder *> binders, idx_t projection_index, case_insensitive_map_t<idx_t> &alias_map,
	            expression_map_t<idx_t> &projection_map, idx_t max_count);
	OrderBinder(vector<Binder *> binders, idx_t projection_index, SelectNode &node,
	            case_insensitive_map_t<idx_t> &alias_map, expression_map_t<idx_t> &projection_map);

public:
	unique_ptr<Expression> Bind(unique_ptr<ParsedExpression> expr);

	idx_t MaxCount() {
		return max_count;
	}

	unique_ptr<Expression> CreateExtraReference(unique_ptr<ParsedExpression> expr);

private:
	unique_ptr<Expression> CreateProjectionReference(ParsedExpression &expr, idx_t index);

private:
	vector<Binder *> binders;
	idx_t projection_index;
	idx_t max_count;
	vector<unique_ptr<ParsedExpression>> *extra_list;
	case_insensitive_map_t<idx_t> &alias_map;
	expression_map_t<idx_t> &projection_map;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/query_node/bound_set_operation_node.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! Bound equivalent of SetOperationNode
class BoundSetOperationNode : public BoundQueryNode {
public:
	BoundSetOperationNode() : BoundQueryNode(QueryNodeType::SET_OPERATION_NODE) {
	}

	//! The type of set operation
	SetOperationType setop_type = SetOperationType::NONE;
	//! The left side of the set operation
	unique_ptr<BoundQueryNode> left;
	//! The right side of the set operation
	unique_ptr<BoundQueryNode> right;

	//! Index used by the set operation
	idx_t setop_index;
	//! The binder used by the left side of the set operation
	shared_ptr<Binder> left_binder;
	//! The binder used by the right side of the set operation
	shared_ptr<Binder> right_binder;

public:
	idx_t GetRootIndex() override {
		return setop_index;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/subquery/flatten_dependent_join.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

//! The FlattenDependentJoins class is responsible for pushing the dependent join down into the plan to create a
//! flattened subquery
struct FlattenDependentJoins {
	FlattenDependentJoins(Binder &binder, const vector<CorrelatedColumnInfo> &correlated, bool perform_delim = true,
	                      bool any_join = false);

	//! Detects which Logical Operators have correlated expressions that they are dependent upon, filling the
	//! has_correlated_expressions map.
	bool DetectCorrelatedExpressions(LogicalOperator *op);

	//! Push the dependent join down a LogicalOperator
	unique_ptr<LogicalOperator> PushDownDependentJoin(unique_ptr<LogicalOperator> plan);

	Binder &binder;
	ColumnBinding base_binding;
	idx_t delim_offset;
	idx_t data_offset;
	unordered_map<LogicalOperator *, bool> has_correlated_expressions;
	column_binding_map_t<idx_t> correlated_map;
	column_binding_map_t<idx_t> replacement_map;
	const vector<CorrelatedColumnInfo> &correlated_columns;
	vector<LogicalType> delim_types;

	bool perform_delim;
	bool any_join;

private:
	unique_ptr<LogicalOperator> PushDownDependentJoinInternal(unique_ptr<LogicalOperator> plan,
	                                                          bool &parent_propagate_null_values);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_table_function.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Represents a reference to a table-producing function call
class BoundTableFunction : public BoundTableRef {
public:
	explicit BoundTableFunction(unique_ptr<LogicalOperator> get)
	    : BoundTableRef(TableReferenceType::TABLE_FUNCTION), get(move(get)) {
	}

	unique_ptr<LogicalOperator> get;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/index_binder.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class BoundColumnRefExpression;

//! The INDEX binder is responsible for binding an expression within an Index statement
class IndexBinder : public ExpressionBinder {
public:
	IndexBinder(Binder &binder, ClientContext &context);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/parsed_data/bound_create_function_info.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class CatalogEntry;

struct BoundCreateFunctionInfo {
	explicit BoundCreateFunctionInfo(unique_ptr<CreateInfo> base) : base(move(base)) {
	}

	//! The schema to create the table in
	SchemaCatalogEntry *schema;
	//! The base CreateInfo object
	unique_ptr<CreateInfo> base;

	CreateMacroInfo &Base() {
		return (CreateMacroInfo &)*base;
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_basetableref.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class TableCatalogEntry;

//! Represents a TableReference to a base table in the schema
class BoundBaseTableRef : public BoundTableRef {
public:
	BoundBaseTableRef(TableCatalogEntry *table, unique_ptr<LogicalOperator> get)
	    : BoundTableRef(TableReferenceType::BASE_TABLE), table(table), get(move(get)) {
	}

	TableCatalogEntry *table;
	unique_ptr<LogicalOperator> get;
};
} // namespace duckdb




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/check_binder.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {
//! The CHECK binder is responsible for binding an expression within a CHECK constraint
class CheckBinder : public ExpressionBinder {
public:
	CheckBinder(Binder &binder, ClientContext &context, string table, vector<ColumnDefinition> &columns,
	            unordered_set<column_t> &bound_columns);

	string table;
	vector<ColumnDefinition> &columns;
	unordered_set<column_t> &bound_columns;

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	BindResult BindCheckColumn(ColumnRefExpression &expr);

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/returning_binder.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The RETURNING binder is responsible for binding expressions within the RETURNING statement
class ReturningBinder : public ExpressionBinder {
public:
	ReturningBinder(Binder &binder, ClientContext &context);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/insert_binder.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The INSERT binder is responsible for binding expressions within the VALUES of an INSERT statement
class InsertBinder : public ExpressionBinder {
public:
	InsertBinder(Binder &binder, ClientContext &context);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/update_binder.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The UPDATE binder is responsible for binding an expression within an UPDATE statement
class UpdateBinder : public ExpressionBinder {
public:
	UpdateBinder(Binder &binder, ClientContext &context);

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_crossproductref.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Represents a cross product
class BoundCrossProductRef : public BoundTableRef {
public:
	BoundCrossProductRef() : BoundTableRef(TableReferenceType::CROSS_PRODUCT) {
	}

	//! The binder used to bind the LHS of the cross product
	shared_ptr<Binder> left_binder;
	//! The binder used to bind the RHS of the cross product
	shared_ptr<Binder> right_binder;
	//! The left hand side of the cross product
	unique_ptr<BoundTableRef> left;
	//! The right hand side of the cross product
	unique_ptr<BoundTableRef> right;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_subqueryref.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! Represents a cross product
class BoundSubqueryRef : public BoundTableRef {
public:
	BoundSubqueryRef(shared_ptr<Binder> binder_p, unique_ptr<BoundQueryNode> subquery)
	    : BoundTableRef(TableReferenceType::SUBQUERY), binder(move(binder_p)), subquery(move(subquery)) {
	}

	//! The binder used to bind the subquery
	shared_ptr<Binder> binder;
	//! The bound subquery node
	unique_ptr<BoundQueryNode> subquery;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_cteref.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

class BoundCTERef : public BoundTableRef {
public:
	BoundCTERef(idx_t bind_index, idx_t cte_index)
	    : BoundTableRef(TableReferenceType::CTE), bind_index(bind_index), cte_index(cte_index) {
	}

	//! The set of columns bound to this base table reference
	vector<string> bound_columns;
	//! The types of the values list
	vector<LogicalType> types;
	//! The index in the bind context
	idx_t bind_index;
	//! The index of the cte
	idx_t cte_index;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_dummytableref.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! Represents a cross product
class BoundEmptyTableRef : public BoundTableRef {
public:
	explicit BoundEmptyTableRef(idx_t bind_index) : BoundTableRef(TableReferenceType::EMPTY), bind_index(bind_index) {
	}
	idx_t bind_index;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_expressionlistref.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
//! Represents a TableReference to a base table in the schema
class BoundExpressionListRef : public BoundTableRef {
public:
	BoundExpressionListRef() : BoundTableRef(TableReferenceType::EXPRESSION_LIST) {
	}

	//! The bound VALUES list
	vector<vector<unique_ptr<Expression>>> values;
	//! The generated names of the values list
	vector<string> names;
	//! The types of the values list
	vector<LogicalType> types;
	//! The index in the bind context
	idx_t bind_index;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/tableref/bound_joinref.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

//! Represents a join
class BoundJoinRef : public BoundTableRef {
public:
	BoundJoinRef() : BoundTableRef(TableReferenceType::JOIN) {
	}

	//! The binder used to bind the LHS of the join
	shared_ptr<Binder> left_binder;
	//! The binder used to bind the RHS of the join
	shared_ptr<Binder> right_binder;
	//! The left hand side of the join
	unique_ptr<BoundTableRef> left;
	//! The right hand side of the join
	unique_ptr<BoundTableRef> right;
	//! The join condition
	unique_ptr<Expression> condition;
	//! The join type
	JoinType type;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/expression_binder/relation_binder.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! The relation binder is a binder used to bind expressions in the relation API
class RelationBinder : public ExpressionBinder {
public:
	RelationBinder(Binder &binder, ClientContext &context, string op);

	string op;

protected:
	BindResult BindExpression(unique_ptr<ParsedExpression> *expr_ptr, idx_t depth,
	                          bool root_expression = false) override;

	string UnsupportedAggregateMessage() override;
};

} // namespace duckdb








//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/subquery/has_correlated_expressions.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Helper class to recursively detect correlated expressions inside a single LogicalOperator
class HasCorrelatedExpressions : public LogicalOperatorVisitor {
public:
	explicit HasCorrelatedExpressions(const vector<CorrelatedColumnInfo> &correlated);

	void VisitOperator(LogicalOperator &op) override;

	bool has_correlated_expressions;

protected:
	unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr) override;
	unique_ptr<Expression> VisitReplace(BoundSubqueryExpression &expr, unique_ptr<Expression> *expr_ptr) override;

	const vector<CorrelatedColumnInfo> &correlated_columns;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/planner/subquery/rewrite_correlated_expressions.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! Helper class to rewrite correlated expressions within a single LogicalOperator
class RewriteCorrelatedExpressions : public LogicalOperatorVisitor {
public:
	RewriteCorrelatedExpressions(ColumnBinding base_binding, column_binding_map_t<idx_t> &correlated_map);

	void VisitOperator(LogicalOperator &op) override;

protected:
	unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr) override;
	unique_ptr<Expression> VisitReplace(BoundSubqueryExpression &expr, unique_ptr<Expression> *expr_ptr) override;

private:
	//! Helper class used to recursively rewrite correlated expressions within nested subqueries.
	class RewriteCorrelatedRecursive {
	public:
		RewriteCorrelatedRecursive(BoundSubqueryExpression &parent, ColumnBinding base_binding,
		                           column_binding_map_t<idx_t> &correlated_map);

		void RewriteCorrelatedSubquery(BoundSubqueryExpression &expr);
		void RewriteCorrelatedExpressions(Expression &child);

		BoundSubqueryExpression &parent;
		ColumnBinding base_binding;
		column_binding_map_t<idx_t> &correlated_map;
	};

private:
	ColumnBinding base_binding;
	column_binding_map_t<idx_t> &correlated_map;
};

//! Helper class that rewrites COUNT aggregates into a CASE expression turning NULL into 0 after a LEFT OUTER JOIN
class RewriteCountAggregates : public LogicalOperatorVisitor {
public:
	explicit RewriteCountAggregates(column_binding_map_t<idx_t> &replacement_map);

	unique_ptr<Expression> VisitReplace(BoundColumnRefExpression &expr, unique_ptr<Expression> *expr_ptr) override;

	column_binding_map_t<idx_t> &replacement_map;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//						 DuckDB
//
// duckdb/parallel/concurrentqueue.hpp
//
//
//===----------------------------------------------------------------------===//

#ifndef DUCKDB_NO_THREADS

#else

#include <cstddef>
#include <deque>
#include <queue>

namespace duckdb_moodycamel {

template <typename T>
class ConcurrentQueue;
template <typename T>
class BlockingConcurrentQueue;

struct ProducerToken {
	//! Constructor
	template <typename T, typename Traits>
	explicit ProducerToken(ConcurrentQueue<T> &);
	//! Constructor
	template <typename T, typename Traits>
	explicit ProducerToken(BlockingConcurrentQueue<T> &);
	//! Constructor
	ProducerToken(ProducerToken &&) {
	}
	//! Is valid token?
	inline bool valid() const {
		return true;
	}
};

template <typename T>
class ConcurrentQueue {
private:
	//! The queue
	std::queue<T, std::deque<T>> q;

public:
	//! Constructor
	ConcurrentQueue() = default;
	//! Constructor
	explicit ConcurrentQueue(size_t capacity) {
		q.reserve(capacity);
	}

	//! Enqueue item
	template <typename U>
	bool enqueue(U &&item) {
		q.push(std::forward<U>(item));
		return true;
	}
	//! Try to dequeue an item
	bool try_dequeue(T &item) {
		if (q.empty()) {
			return false;
		}
		item = std::move(q.front());
		q.pop();
		return true;
	}
};

} // namespace duckdb_moodycamel

#endif
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/checkpoint/table_data_reader.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/checkpoint_manager.hpp
//
//
//===----------------------------------------------------------------------===//







//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/meta_block_writer.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {
class DatabaseInstance;

//! This struct is responsible for writing metadata to disk
class MetaBlockWriter : public Serializer {
public:
	MetaBlockWriter(DatabaseInstance &db, block_id_t initial_block_id = INVALID_BLOCK);
	~MetaBlockWriter() override;

	DatabaseInstance &db;
	unique_ptr<Block> block;
	set<block_id_t> written_blocks;
	idx_t offset;

public:
	BlockPointer GetBlockPointer();
	void Flush();

	void WriteData(const_data_ptr_t buffer, idx_t write_size) override;

protected:
	virtual block_id_t GetNextBlockId();
};

} // namespace duckdb



namespace duckdb {
class DatabaseInstance;
class ClientContext;
class ColumnSegment;
class MetaBlockReader;
class SchemaCatalogEntry;
class SequenceCatalogEntry;
class TableCatalogEntry;
class ViewCatalogEntry;
class TypeCatalogEntry;

struct PartialColumnSegment {
	ColumnSegment *segment;
	uint32_t offset_in_block;
};

struct PartialBlock {
	block_id_t block_id;
	//! The block handle that stores this block
	shared_ptr<BlockHandle> block;
	//! The segments that are involved in the partial block
	vector<PartialColumnSegment> segments;

	void FlushToDisk(DatabaseInstance &db);
};

//! CheckpointManager is responsible for checkpointing the database
class CheckpointManager {
public:
	static constexpr const idx_t PARTIAL_BLOCK_THRESHOLD = Storage::BLOCK_SIZE / 5 * 4;

public:
	explicit CheckpointManager(DatabaseInstance &db);

	//! The database
	DatabaseInstance &db;
	//! The metadata writer is responsible for writing schema information
	unique_ptr<MetaBlockWriter> metadata_writer;
	//! The table data writer is responsible for writing the DataPointers used by the table chunks
	unique_ptr<MetaBlockWriter> tabledata_writer;

public:
	//! Checkpoint the current state of the WAL and flush it to the main storage. This should be called BEFORE any
	//! connction is available because right now the checkpointing cannot be done online. (TODO)
	void CreateCheckpoint();
	//! Load from a stored checkpoint
	void LoadFromStorage();

	//! Try to obtain a partially filled block that can fit "segment_size" bytes
	//! If successful, returns true and returns the block_id and offset_in_block to write to
	//! Otherwise, returns false
	bool GetPartialBlock(ColumnSegment *segment, idx_t segment_size, block_id_t &block_id, uint32_t &offset_in_block,
	                     PartialBlock *&partial_block_ptr, unique_ptr<PartialBlock> &owned_partial_block);

	//! Register a partially filled block that is filled with "segment_size" entries
	void RegisterPartialBlock(ColumnSegment *segment, idx_t segment_size, block_id_t block_id);

	//! Flush any remaining partial segments to disk
	void FlushPartialSegments();

private:
	void WriteSchema(SchemaCatalogEntry &schema);
	void WriteTable(TableCatalogEntry &table);
	void WriteView(ViewCatalogEntry &table);
	void WriteSequence(SequenceCatalogEntry &table);
	void WriteMacro(ScalarMacroCatalogEntry &table);
	void WriteTableMacro(TableMacroCatalogEntry &table);
	void WriteType(TypeCatalogEntry &table);

	void ReadSchema(ClientContext &context, MetaBlockReader &reader);
	void ReadTable(ClientContext &context, MetaBlockReader &reader);
	void ReadView(ClientContext &context, MetaBlockReader &reader);
	void ReadSequence(ClientContext &context, MetaBlockReader &reader);
	void ReadMacro(ClientContext &context, MetaBlockReader &reader);
	void ReadTableMacro(ClientContext &context, MetaBlockReader &reader);
	void ReadType(ClientContext &context, MetaBlockReader &reader);

private:
	//! A map of (available space -> PartialBlock) for partially filled blocks
	//! This is a multimap because there might be outstanding partial blocks with the same amount of left-over space
	multimap<idx_t, unique_ptr<PartialBlock>> partially_filled_blocks;
};

} // namespace duckdb


namespace duckdb {
struct BoundCreateTableInfo;

//! The table data reader is responsible for reading the data of a table from the block manager
class TableDataReader {
public:
	TableDataReader(MetaBlockReader &reader, BoundCreateTableInfo &info);

	void ReadTableData();

private:
	MetaBlockReader &reader;
	BoundCreateTableInfo &info;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/meta_block_reader.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
class BlockHandle;
class BufferHandle;
class DatabaseInstance;

//! This struct is responsible for reading meta data from disk
class MetaBlockReader : public Deserializer {
public:
	MetaBlockReader(DatabaseInstance &db, block_id_t block);
	~MetaBlockReader() override;

	DatabaseInstance &db;
	shared_ptr<BlockHandle> block;
	BufferHandle handle;
	idx_t offset;
	block_id_t next_block;

public:
	//! Read content of size read_size into the buffer
	void ReadData(data_ptr_t buffer, idx_t read_size) override;

private:
	void ReadNewBlock(block_id_t id);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/checkpoint/table_data_writer.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class CheckpointManager;
class ColumnData;
class ColumnSegment;
class RowGroup;
class BaseStatistics;
class SegmentStatistics;

//! The table data writer is responsible for writing the data of a table to the block manager
class TableDataWriter {
	friend class ColumnData;

public:
	TableDataWriter(DatabaseInstance &db, CheckpointManager &checkpoint_manager, TableCatalogEntry &table,
	                MetaBlockWriter &meta_writer);
	~TableDataWriter();

	BlockPointer WriteTableData();

	MetaBlockWriter &GetMetaWriter() {
		return meta_writer;
	}

	CheckpointManager &GetCheckpointManager() {
		return checkpoint_manager;
	}

	CompressionType GetColumnCompressionType(idx_t i);

private:
	CheckpointManager &checkpoint_manager;
	TableCatalogEntry &table;
	MetaBlockWriter &meta_writer;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/checkpoint/write_overflow_strings_to_disk.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/checkpoint/string_checkpoint_state.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {

class OverflowStringWriter {
public:
	virtual ~OverflowStringWriter() {
	}

	virtual void WriteString(string_t string, block_id_t &result_block, int32_t &result_offset) = 0;
};

struct StringBlock {
	shared_ptr<BlockHandle> block;
	idx_t offset;
	idx_t size;
	unique_ptr<StringBlock> next;
};

struct string_location_t {
	string_location_t(block_id_t block_id, int32_t offset) : block_id(block_id), offset(offset) {
	}
	string_location_t() {
	}
	bool IsValid() {
		return offset < Storage::BLOCK_SIZE && (block_id == INVALID_BLOCK || block_id >= MAXIMUM_BLOCK);
	}
	block_id_t block_id;
	int32_t offset;
};

struct UncompressedStringSegmentState : public CompressedSegmentState {
	~UncompressedStringSegmentState();

	//! The string block holding strings that do not fit in the main block
	//! FIXME: this should be replaced by a heap that also allows freeing of unused strings
	unique_ptr<StringBlock> head;
	//! Overflow string writer (if any), if not set overflow strings will be written to memory blocks
	unique_ptr<OverflowStringWriter> overflow_writer;
	//! Map of block id to string block
	unordered_map<block_id_t, StringBlock *> overflow_blocks;
};

} // namespace duckdb


namespace duckdb {

class WriteOverflowStringsToDisk : public OverflowStringWriter {
public:
	explicit WriteOverflowStringsToDisk(DatabaseInstance &db);
	~WriteOverflowStringsToDisk() override;

	//! The checkpoint manager
	DatabaseInstance &db;

	//! Temporary buffer
	BufferHandle handle;
	//! The block on-disk to which we are writing
	block_id_t block_id;
	//! The offset within the current block
	idx_t offset;

	static constexpr idx_t STRING_SPACE = Storage::BLOCK_SIZE - sizeof(block_id_t);

public:
	void WriteString(string_t string, block_id_t &result_block, int32_t &result_offset) override;

private:
	void AllocateNewBlock(block_id_t new_block_id);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/common/bitpacking.hpp
//
//
//===----------------------------------------------------------------------===//





// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #12
// See the end of this file for a list

/**
* This code is released under the
* Apache License Version 2.0 http://www.apache.org/licenses/.
*
* (c) Daniel Lemire, http://lemire.me/en/
*/



// LICENSE_CHANGE_BEGIN
// The following code up to LICENSE_CHANGE_END is subject to THIRD PARTY LICENSE #12
// See the end of this file for a list

/**
 * This code is released under the
 * Apache License Version 2.0 http://www.apache.org/licenses/.
 *
 * (c) Daniel Lemire, http://fastpforlib.me/en/
 */

#include <cinttypes>
#include <string>

namespace duckdb_fastpforlib {
namespace internal {

// Unpacks 8 uint8_t values
void __fastunpack0(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack1(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack2(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack3(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack4(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack5(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack6(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack7(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastunpack8(const uint8_t *__restrict in, uint8_t *__restrict out);

// Unpacks 16 uint16_t values
void __fastunpack0(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack1(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack2(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack3(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack4(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack5(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack6(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack7(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack8(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack9(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack10(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack11(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack12(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack13(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack14(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack15(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastunpack16(const uint16_t *__restrict in, uint16_t *__restrict out);

// Unpacks 32 uint32_t values
void __fastunpack0(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack1(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack2(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack3(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack4(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack5(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack6(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack7(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack8(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack9(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack10(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack11(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack12(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack13(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack14(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack15(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack16(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack17(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack18(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack19(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack20(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack21(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack22(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack23(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack24(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack25(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack26(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack27(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack28(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack29(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack30(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack31(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastunpack32(const uint32_t *__restrict in, uint32_t *__restrict out);

// Unpacks 32 uint64_t values
void __fastunpack0(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack1(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack2(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack3(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack4(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack5(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack6(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack7(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack8(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack9(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack10(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack11(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack12(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack13(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack14(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack15(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack16(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack17(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack18(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack19(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack20(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack21(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack22(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack23(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack24(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack25(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack26(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack27(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack28(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack29(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack30(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack31(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack32(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack33(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack34(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack35(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack36(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack37(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack38(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack39(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack40(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack41(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack42(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack43(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack44(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack45(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack46(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack47(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack48(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack49(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack50(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack51(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack52(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack53(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack54(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack55(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack56(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack57(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack58(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack59(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack60(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack61(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack62(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack63(const uint32_t *__restrict in, uint64_t *__restrict out);
void __fastunpack64(const uint32_t *__restrict in, uint64_t *__restrict out);

// Packs 8 int8_t values
void __fastpack0(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack1(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack2(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack3(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack4(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack5(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack6(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack7(const uint8_t *__restrict in, uint8_t *__restrict out);
void __fastpack8(const uint8_t *__restrict in, uint8_t *__restrict out);

// Packs 16 int16_t values
void __fastpack0(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack1(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack2(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack3(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack4(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack5(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack6(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack7(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack8(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack9(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack10(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack11(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack12(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack13(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack14(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack15(const uint16_t *__restrict in, uint16_t *__restrict out);
void __fastpack16(const uint16_t *__restrict in, uint16_t *__restrict out);

// Packs 32 int32_t values
void __fastpack0(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack1(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack2(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack3(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack4(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack5(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack6(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack7(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack8(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack9(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack10(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack11(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack12(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack13(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack14(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack15(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack16(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack17(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack18(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack19(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack20(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack21(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack22(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack23(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack24(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack25(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack26(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack27(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack28(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack29(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack30(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack31(const uint32_t *__restrict in, uint32_t *__restrict out);
void __fastpack32(const uint32_t *__restrict in, uint32_t *__restrict out);

// Packs 32 int64_t values
void __fastpack0(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack1(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack2(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack3(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack4(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack5(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack6(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack7(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack8(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack9(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack10(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack11(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack12(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack13(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack14(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack15(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack16(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack17(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack18(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack19(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack20(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack21(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack22(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack23(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack24(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack25(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack26(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack27(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack28(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack29(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack30(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack31(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack32(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack33(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack34(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack35(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack36(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack37(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack38(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack39(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack40(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack41(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack42(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack43(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack44(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack45(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack46(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack47(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack48(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack49(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack50(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack51(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack52(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack53(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack54(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack55(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack56(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack57(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack58(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack59(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack60(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack61(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack62(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack63(const uint64_t *__restrict in, uint32_t *__restrict out);
void __fastpack64(const uint64_t *__restrict in, uint32_t *__restrict out);
} // namespace internal
} // namespace duckdb_fastpforlib


// LICENSE_CHANGE_END



#include <stdexcept>

namespace duckdb_fastpforlib {

namespace internal {

// Note that this only packs 8 values
inline void fastunpack_quarter(const uint8_t *__restrict in, uint8_t *__restrict out, const uint32_t bit) {
	// Could have used function pointers instead of switch.
	// Switch calls do offer the compiler more opportunities for optimization in
	// theory. In this case, it makes no difference with a good compiler.
	switch (bit) {
	case 0:
		internal::__fastunpack0(in, out);
		break;
	case 1:
		internal::__fastunpack1(in, out);
		break;
	case 2:
		internal::__fastunpack2(in, out);
		break;
	case 3:
		internal::__fastunpack3(in, out);
		break;
	case 4:
		internal::__fastunpack4(in, out);
		break;
	case 5:
		internal::__fastunpack5(in, out);
		break;
	case 6:
		internal::__fastunpack6(in, out);
		break;
	case 7:
		internal::__fastunpack7(in, out);
		break;
	case 8:
		internal::__fastunpack8(in, out);
		break;
	default:
		throw std::logic_error("Invalid bit width for bitpacking");
	}
}

// Note that this only packs 8 values
inline void fastpack_quarter(const uint8_t *__restrict in, uint8_t *__restrict out, const uint32_t bit) {
	// Could have used function pointers instead of switch.
	// Switch calls do offer the compiler more opportunities for optimization in
	// theory. In this case, it makes no difference with a good compiler.
	switch (bit) {
	case 0:
		internal::__fastpack0(in, out);
		break;
	case 1:
		internal::__fastpack1(in, out);
		break;
	case 2:
		internal::__fastpack2(in, out);
		break;
	case 3:
		internal::__fastpack3(in, out);
		break;
	case 4:
		internal::__fastpack4(in, out);
		break;
	case 5:
		internal::__fastpack5(in, out);
		break;
	case 6:
		internal::__fastpack6(in, out);
		break;
	case 7:
		internal::__fastpack7(in, out);
		break;
	case 8:
		internal::__fastpack8(in, out);
		break;
	default:
		throw std::logic_error("Invalid bit width for bitpacking");
	}
}

// Note that this only packs 16 values
inline void fastunpack_half(const uint16_t *__restrict in, uint16_t *__restrict out, const uint32_t bit) {
	// Could have used function pointers instead of switch.
	// Switch calls do offer the compiler more opportunities for optimization in
	// theory. In this case, it makes no difference with a good compiler.
	switch (bit) {
	case 0:
		internal::__fastunpack0(in, out);
		break;
	case 1:
		internal::__fastunpack1(in, out);
		break;
	case 2:
		internal::__fastunpack2(in, out);
		break;
	case 3:
		internal::__fastunpack3(in, out);
		break;
	case 4:
		internal::__fastunpack4(in, out);
		break;
	case 5:
		internal::__fastunpack5(in, out);
		break;
	case 6:
		internal::__fastunpack6(in, out);
		break;
	case 7:
		internal::__fastunpack7(in, out);
		break;
	case 8:
		internal::__fastunpack8(in, out);
		break;
	case 9:
		internal::__fastunpack9(in, out);
		break;
	case 10:
		internal::__fastunpack10(in, out);
		break;
	case 11:
		internal::__fastunpack11(in, out);
		break;
	case 12:
		internal::__fastunpack12(in, out);
		break;
	case 13:
		internal::__fastunpack13(in, out);
		break;
	case 14:
		internal::__fastunpack14(in, out);
		break;
	case 15:
		internal::__fastunpack15(in, out);
		break;
	case 16:
		internal::__fastunpack16(in, out);
		break;
	default:
		throw std::logic_error("Invalid bit width for bitpacking");
	}
}

// Note that this only packs 16 values
inline void fastpack_half(const uint16_t *__restrict in, uint16_t *__restrict out, const uint32_t bit) {
	// Could have used function pointers instead of switch.
	// Switch calls do offer the compiler more opportunities for optimization in
	// theory. In this case, it makes no difference with a good compiler.
	switch (bit) {
	case 0:
		internal::__fastpack0(in, out);
		break;
	case 1:
		internal::__fastpack1(in, out);
		break;
	case 2:
		internal::__fastpack2(in, out);
		break;
	case 3:
		internal::__fastpack3(in, out);
		break;
	case 4:
		internal::__fastpack4(in, out);
		break;
	case 5:
		internal::__fastpack5(in, out);
		break;
	case 6:
		internal::__fastpack6(in, out);
		break;
	case 7:
		internal::__fastpack7(in, out);
		break;
	case 8:
		internal::__fastpack8(in, out);
		break;
	case 9:
		internal::__fastpack9(in, out);
		break;
	case 10:
		internal::__fastpack10(in, out);
		break;
	case 11:
		internal::__fastpack11(in, out);
		break;
	case 12:
		internal::__fastpack12(in, out);
		break;
	case 13:
		internal::__fastpack13(in, out);
		break;
	case 14:
		internal::__fastpack14(in, out);
		break;
	case 15:
		internal::__fastpack15(in, out);
		break;
	case 16:
		internal::__fastpack16(in, out);
		break;
	default:
		throw std::logic_error("Invalid bit width for bitpacking");
	}
}
}

inline void fastunpack(const uint8_t *__restrict in, uint8_t *__restrict out, const uint32_t bit) {
	for (uint8_t i = 0; i < 4; i++) {
		internal::fastunpack_quarter(in + (i*bit), out+(i*8), bit);
	}
}

inline void fastunpack(const uint16_t *__restrict in, uint16_t *__restrict out, const uint32_t bit) {
	internal::fastunpack_half(in, out, bit);
	internal::fastunpack_half(in + bit, out+16, bit);
}

inline void fastunpack(const uint32_t *__restrict in,
                       uint32_t *__restrict out, const uint32_t bit) {
  // Could have used function pointers instead of switch.
  // Switch calls do offer the compiler more opportunities for optimization in
  // theory. In this case, it makes no difference with a good compiler.
  switch (bit) {
  case 0:
    internal::__fastunpack0(in, out);
    break;
  case 1:
    internal::__fastunpack1(in, out);
    break;
  case 2:
    internal::__fastunpack2(in, out);
    break;
  case 3:
    internal::__fastunpack3(in, out);
    break;
  case 4:
    internal::__fastunpack4(in, out);
    break;
  case 5:
    internal::__fastunpack5(in, out);
    break;
  case 6:
    internal::__fastunpack6(in, out);
    break;
  case 7:
    internal::__fastunpack7(in, out);
    break;
  case 8:
    internal::__fastunpack8(in, out);
    break;
  case 9:
    internal::__fastunpack9(in, out);
    break;
  case 10:
    internal::__fastunpack10(in, out);
    break;
  case 11:
    internal::__fastunpack11(in, out);
    break;
  case 12:
    internal::__fastunpack12(in, out);
    break;
  case 13:
    internal::__fastunpack13(in, out);
    break;
  case 14:
    internal::__fastunpack14(in, out);
    break;
  case 15:
    internal::__fastunpack15(in, out);
    break;
  case 16:
    internal::__fastunpack16(in, out);
    break;
  case 17:
    internal::__fastunpack17(in, out);
    break;
  case 18:
    internal::__fastunpack18(in, out);
    break;
  case 19:
    internal::__fastunpack19(in, out);
    break;
  case 20:
    internal::__fastunpack20(in, out);
    break;
  case 21:
    internal::__fastunpack21(in, out);
    break;
  case 22:
    internal::__fastunpack22(in, out);
    break;
  case 23:
    internal::__fastunpack23(in, out);
    break;
  case 24:
    internal::__fastunpack24(in, out);
    break;
  case 25:
    internal::__fastunpack25(in, out);
    break;
  case 26:
    internal::__fastunpack26(in, out);
    break;
  case 27:
    internal::__fastunpack27(in, out);
    break;
  case 28:
    internal::__fastunpack28(in, out);
    break;
  case 29:
    internal::__fastunpack29(in, out);
    break;
  case 30:
    internal::__fastunpack30(in, out);
    break;
  case 31:
    internal::__fastunpack31(in, out);
    break;
  case 32:
    internal::__fastunpack32(in, out);
    break;
  default:
    throw std::logic_error("Invalid bit width for bitpacking");
  }
}

inline void fastunpack(const uint32_t *__restrict in,
                       uint64_t *__restrict out, const uint32_t bit) {
  // Could have used function pointers instead of switch.
  // Switch calls do offer the compiler more opportunities for optimization in
  // theory. In this case, it makes no difference with a good compiler.
  switch (bit) {
  case 0:
    internal::__fastunpack0(in, out);
    break;
  case 1:
    internal::__fastunpack1(in, out);
    break;
  case 2:
    internal::__fastunpack2(in, out);
    break;
  case 3:
    internal::__fastunpack3(in, out);
    break;
  case 4:
    internal::__fastunpack4(in, out);
    break;
  case 5:
    internal::__fastunpack5(in, out);
    break;
  case 6:
    internal::__fastunpack6(in, out);
    break;
  case 7:
    internal::__fastunpack7(in, out);
    break;
  case 8:
    internal::__fastunpack8(in, out);
    break;
  case 9:
    internal::__fastunpack9(in, out);
    break;
  case 10:
    internal::__fastunpack10(in, out);
    break;
  case 11:
    internal::__fastunpack11(in, out);
    break;
  case 12:
    internal::__fastunpack12(in, out);
    break;
  case 13:
    internal::__fastunpack13(in, out);
    break;
  case 14:
    internal::__fastunpack14(in, out);
    break;
  case 15:
    internal::__fastunpack15(in, out);
    break;
  case 16:
    internal::__fastunpack16(in, out);
    break;
  case 17:
    internal::__fastunpack17(in, out);
    break;
  case 18:
    internal::__fastunpack18(in, out);
    break;
  case 19:
    internal::__fastunpack19(in, out);
    break;
  case 20:
    internal::__fastunpack20(in, out);
    break;
  case 21:
    internal::__fastunpack21(in, out);
    break;
  case 22:
    internal::__fastunpack22(in, out);
    break;
  case 23:
    internal::__fastunpack23(in, out);
    break;
  case 24:
    internal::__fastunpack24(in, out);
    break;
  case 25:
    internal::__fastunpack25(in, out);
    break;
  case 26:
    internal::__fastunpack26(in, out);
    break;
  case 27:
    internal::__fastunpack27(in, out);
    break;
  case 28:
    internal::__fastunpack28(in, out);
    break;
  case 29:
    internal::__fastunpack29(in, out);
    break;
  case 30:
    internal::__fastunpack30(in, out);
    break;
  case 31:
    internal::__fastunpack31(in, out);
    break;
  case 32:
    internal::__fastunpack32(in, out);
    break;
  case 33:
    internal::__fastunpack33(in, out);
    break;
  case 34:
    internal::__fastunpack34(in, out);
    break;
  case 35:
    internal::__fastunpack35(in, out);
    break;
  case 36:
    internal::__fastunpack36(in, out);
    break;
  case 37:
    internal::__fastunpack37(in, out);
    break;
  case 38:
    internal::__fastunpack38(in, out);
    break;
  case 39:
    internal::__fastunpack39(in, out);
    break;
  case 40:
    internal::__fastunpack40(in, out);
    break;
  case 41:
    internal::__fastunpack41(in, out);
    break;
  case 42:
    internal::__fastunpack42(in, out);
    break;
  case 43:
    internal::__fastunpack43(in, out);
    break;
  case 44:
    internal::__fastunpack44(in, out);
    break;
  case 45:
    internal::__fastunpack45(in, out);
    break;
  case 46:
    internal::__fastunpack46(in, out);
    break;
  case 47:
    internal::__fastunpack47(in, out);
    break;
  case 48:
    internal::__fastunpack48(in, out);
    break;
  case 49:
    internal::__fastunpack49(in, out);
    break;
  case 50:
    internal::__fastunpack50(in, out);
    break;
  case 51:
    internal::__fastunpack51(in, out);
    break;
  case 52:
    internal::__fastunpack52(in, out);
    break;
  case 53:
    internal::__fastunpack53(in, out);
    break;
  case 54:
    internal::__fastunpack54(in, out);
    break;
  case 55:
    internal::__fastunpack55(in, out);
    break;
  case 56:
    internal::__fastunpack56(in, out);
    break;
  case 57:
    internal::__fastunpack57(in, out);
    break;
  case 58:
    internal::__fastunpack58(in, out);
    break;
  case 59:
    internal::__fastunpack59(in, out);
    break;
  case 60:
    internal::__fastunpack60(in, out);
    break;
  case 61:
    internal::__fastunpack61(in, out);
    break;
  case 62:
    internal::__fastunpack62(in, out);
    break;
  case 63:
    internal::__fastunpack63(in, out);
    break;
  case 64:
    internal::__fastunpack64(in, out);
    break;
  default:
	throw std::logic_error("Invalid bit width for bitpacking");
  }
}

inline void fastpack(const uint8_t *__restrict in, uint8_t *__restrict out, const uint32_t bit) {

	for (uint8_t i = 0; i < 4; i++) {
		internal::fastpack_quarter(in+(i*8), out + (i*bit), bit);
	}
}

inline void fastpack(const uint16_t *__restrict in, uint16_t *__restrict out, const uint32_t bit) {
	internal::fastpack_half(in, out, bit);
	internal::fastpack_half(in+16, out + bit, bit);
}

inline void fastpack(const uint32_t *__restrict in,
                     uint32_t *__restrict out, const uint32_t bit) {
  // Could have used function pointers instead of switch.
  // Switch calls do offer the compiler more opportunities for optimization in
  // theory. In this case, it makes no difference with a good compiler.
  switch (bit) {
  case 0:
    internal::__fastpack0(in, out);
    break;
  case 1:
    internal::__fastpack1(in, out);
    break;
  case 2:
    internal::__fastpack2(in, out);
    break;
  case 3:
    internal::__fastpack3(in, out);
    break;
  case 4:
    internal::__fastpack4(in, out);
    break;
  case 5:
    internal::__fastpack5(in, out);
    break;
  case 6:
    internal::__fastpack6(in, out);
    break;
  case 7:
    internal::__fastpack7(in, out);
    break;
  case 8:
    internal::__fastpack8(in, out);
    break;
  case 9:
    internal::__fastpack9(in, out);
    break;
  case 10:
    internal::__fastpack10(in, out);
    break;
  case 11:
    internal::__fastpack11(in, out);
    break;
  case 12:
    internal::__fastpack12(in, out);
    break;
  case 13:
    internal::__fastpack13(in, out);
    break;
  case 14:
    internal::__fastpack14(in, out);
    break;
  case 15:
    internal::__fastpack15(in, out);
    break;
  case 16:
    internal::__fastpack16(in, out);
    break;
  case 17:
    internal::__fastpack17(in, out);
    break;
  case 18:
    internal::__fastpack18(in, out);
    break;
  case 19:
    internal::__fastpack19(in, out);
    break;
  case 20:
    internal::__fastpack20(in, out);
    break;
  case 21:
    internal::__fastpack21(in, out);
    break;
  case 22:
    internal::__fastpack22(in, out);
    break;
  case 23:
    internal::__fastpack23(in, out);
    break;
  case 24:
    internal::__fastpack24(in, out);
    break;
  case 25:
    internal::__fastpack25(in, out);
    break;
  case 26:
    internal::__fastpack26(in, out);
    break;
  case 27:
    internal::__fastpack27(in, out);
    break;
  case 28:
    internal::__fastpack28(in, out);
    break;
  case 29:
    internal::__fastpack29(in, out);
    break;
  case 30:
    internal::__fastpack30(in, out);
    break;
  case 31:
    internal::__fastpack31(in, out);
    break;
  case 32:
    internal::__fastpack32(in, out);
    break;
  default:
	throw std::logic_error("Invalid bit width for bitpacking");
  }
}

inline void fastpack(const uint64_t *__restrict in,
                     uint32_t *__restrict out, const uint32_t bit) {
  switch (bit) {
  case 0:
    internal::__fastpack0(in, out);
    break;
  case 1:
    internal::__fastpack1(in, out);
    break;
  case 2:
    internal::__fastpack2(in, out);
    break;
  case 3:
    internal::__fastpack3(in, out);
    break;
  case 4:
    internal::__fastpack4(in, out);
    break;
  case 5:
    internal::__fastpack5(in, out);
    break;
  case 6:
    internal::__fastpack6(in, out);
    break;
  case 7:
    internal::__fastpack7(in, out);
    break;
  case 8:
    internal::__fastpack8(in, out);
    break;
  case 9:
    internal::__fastpack9(in, out);
    break;
  case 10:
    internal::__fastpack10(in, out);
    break;
  case 11:
    internal::__fastpack11(in, out);
    break;
  case 12:
    internal::__fastpack12(in, out);
    break;
  case 13:
    internal::__fastpack13(in, out);
    break;
  case 14:
    internal::__fastpack14(in, out);
    break;
  case 15:
    internal::__fastpack15(in, out);
    break;
  case 16:
    internal::__fastpack16(in, out);
    break;
  case 17:
    internal::__fastpack17(in, out);
    break;
  case 18:
    internal::__fastpack18(in, out);
    break;
  case 19:
    internal::__fastpack19(in, out);
    break;
  case 20:
    internal::__fastpack20(in, out);
    break;
  case 21:
    internal::__fastpack21(in, out);
    break;
  case 22:
    internal::__fastpack22(in, out);
    break;
  case 23:
    internal::__fastpack23(in, out);
    break;
  case 24:
    internal::__fastpack24(in, out);
    break;
  case 25:
    internal::__fastpack25(in, out);
    break;
  case 26:
    internal::__fastpack26(in, out);
    break;
  case 27:
    internal::__fastpack27(in, out);
    break;
  case 28:
    internal::__fastpack28(in, out);
    break;
  case 29:
    internal::__fastpack29(in, out);
    break;
  case 30:
    internal::__fastpack30(in, out);
    break;
  case 31:
    internal::__fastpack31(in, out);
    break;
  case 32:
    internal::__fastpack32(in, out);
    break;
  case 33:
    internal::__fastpack33(in, out);
    break;
  case 34:
    internal::__fastpack34(in, out);
    break;
  case 35:
    internal::__fastpack35(in, out);
    break;
  case 36:
    internal::__fastpack36(in, out);
    break;
  case 37:
    internal::__fastpack37(in, out);
    break;
  case 38:
    internal::__fastpack38(in, out);
    break;
  case 39:
    internal::__fastpack39(in, out);
    break;
  case 40:
    internal::__fastpack40(in, out);
    break;
  case 41:
    internal::__fastpack41(in, out);
    break;
  case 42:
    internal::__fastpack42(in, out);
    break;
  case 43:
    internal::__fastpack43(in, out);
    break;
  case 44:
    internal::__fastpack44(in, out);
    break;
  case 45:
    internal::__fastpack45(in, out);
    break;
  case 46:
    internal::__fastpack46(in, out);
    break;
  case 47:
    internal::__fastpack47(in, out);
    break;
  case 48:
    internal::__fastpack48(in, out);
    break;
  case 49:
    internal::__fastpack49(in, out);
    break;
  case 50:
    internal::__fastpack50(in, out);
    break;
  case 51:
    internal::__fastpack51(in, out);
    break;
  case 52:
    internal::__fastpack52(in, out);
    break;
  case 53:
    internal::__fastpack53(in, out);
    break;
  case 54:
    internal::__fastpack54(in, out);
    break;
  case 55:
    internal::__fastpack55(in, out);
    break;
  case 56:
    internal::__fastpack56(in, out);
    break;
  case 57:
    internal::__fastpack57(in, out);
    break;
  case 58:
    internal::__fastpack58(in, out);
    break;
  case 59:
    internal::__fastpack59(in, out);
    break;
  case 60:
    internal::__fastpack60(in, out);
    break;
  case 61:
    internal::__fastpack61(in, out);
    break;
  case 62:
    internal::__fastpack62(in, out);
    break;
  case 63:
    internal::__fastpack63(in, out);
    break;
  case 64:
    internal::__fastpack64(in, out);
    break;
  default:
	throw std::logic_error("Invalid bit width for bitpacking");
  }
}
} // namespace fastpfor_lib


// LICENSE_CHANGE_END






namespace duckdb {

using bitpacking_width_t = uint8_t;

class BitpackingPrimitives {

public:
	static constexpr const idx_t BITPACKING_ALGORITHM_GROUP_SIZE = 32;
	static constexpr const idx_t BITPACKING_HEADER_SIZE = sizeof(uint64_t);
	static constexpr const bool BYTE_ALIGNED = false;

	// To ensure enough data is available, use GetRequiredSize() to determine the correct size for dst buffer
	// Note: input should be aligned to BITPACKING_ALGORITHM_GROUP_SIZE for good performance.
	template <class T, bool ASSUME_INPUT_ALIGNED = false>
	inline static void PackBuffer(data_ptr_t dst, T *src, idx_t count, bitpacking_width_t width) {
		if (ASSUME_INPUT_ALIGNED) {
			for (idx_t i = 0; i < count; i += BITPACKING_ALGORITHM_GROUP_SIZE) {
				PackGroup<T>(dst + (i * width) / 8, src + i, width);
			}
		} else {
			idx_t misaligned_count = count % BITPACKING_ALGORITHM_GROUP_SIZE;
			T tmp_buffer[BITPACKING_ALGORITHM_GROUP_SIZE]; // TODO maybe faster on the heap?

			if (misaligned_count) {
				count -= misaligned_count;
			}

			for (idx_t i = 0; i < count; i += BITPACKING_ALGORITHM_GROUP_SIZE) {
				PackGroup<T>(dst + (i * width) / 8, src + i, width);
			}

			// Input was not aligned to BITPACKING_ALGORITHM_GROUP_SIZE, we need a copy
			if (misaligned_count) {
				memcpy(tmp_buffer, src + count, misaligned_count * sizeof(T));
				PackGroup<T>(dst + (count * width) / 8, tmp_buffer, width);
			}
		}
	}

	// Unpacks a block of BITPACKING_ALGORITHM_GROUP_SIZE values
	// Assumes both src and dst to be of the correct size
	template <class T>
	inline static void UnPackBuffer(data_ptr_t dst, data_ptr_t src, idx_t count, bitpacking_width_t width,
	                                bool skip_sign_extension = false) {

		for (idx_t i = 0; i < count; i += BITPACKING_ALGORITHM_GROUP_SIZE) {
			UnPackGroup<T>(dst + i * sizeof(T), src + (i * width) / 8, width, skip_sign_extension);
		}
	}

	// Packs a block of BITPACKING_ALGORITHM_GROUP_SIZE values
	template <class T>
	inline static void PackBlock(data_ptr_t dst, T *src, bitpacking_width_t width) {
		return PackGroup<T>(dst, src, width);
	}

	// Unpacks a block of BITPACKING_ALGORITHM_GROUP_SIZE values
	template <class T>
	inline static void UnPackBlock(data_ptr_t dst, data_ptr_t src, bitpacking_width_t width,
	                               bool skip_sign_extension = false) {
		return UnPackGroup<T>(dst, src, width, skip_sign_extension);
	}

	// Calculates the minimum required number of bits per value that can store all values
	template <class T>
	inline static bitpacking_width_t MinimumBitWidth(T value) {
		return FindMinimumBitWidth<T, BYTE_ALIGNED>(value, value);
	}

	// Calculates the minimum required number of bits per value that can store all values
	template <class T>
	inline static bitpacking_width_t MinimumBitWidth(T *values, idx_t count) {
		return FindMinimumBitWidth<T, BYTE_ALIGNED>(values, count);
	}

	template <class T>
	inline static idx_t GetRequiredSize(idx_t count, bitpacking_width_t width) {
		count = RoundUpToAlgorithmGroupSize(count);
		return ((count * width) / 8);
	}

	template <class T>
	inline static T RoundUpToAlgorithmGroupSize(T num_to_round) {
		int remainder = num_to_round % BITPACKING_ALGORITHM_GROUP_SIZE;
		if (remainder == 0) {
			return num_to_round;
		}

		return num_to_round + BITPACKING_ALGORITHM_GROUP_SIZE - remainder;
	}

private:
	template <class T, bool round_to_next_byte = false>
	static bitpacking_width_t FindMinimumBitWidth(T *values, idx_t count) {
		T min_value = values[0];
		T max_value = values[0];

		for (idx_t i = 1; i < count; i++) {
			if (values[i] > max_value) {
				max_value = values[i];
			}

			if (std::is_signed<T>::value) {
				if (values[i] < min_value) {
					min_value = values[i];
				}
			}
		}

		return FindMinimumBitWidth<T, round_to_next_byte>(min_value, max_value);
	}

	template <class T, bool round_to_next_byte = false>
	static bitpacking_width_t FindMinimumBitWidth(T min_value, T max_value) {
		bitpacking_width_t bitwidth;
		T value;

		if (std::is_signed<T>::value) {
			if (min_value == NumericLimits<T>::Minimum()) {
				// handle special case of the minimal value, as it cannot be negated like all other values.
				return sizeof(T) * 8;
			} else {
				value = MaxValue((T)-min_value, max_value);
			}
		} else {
			value = max_value;
		}

		if (value == 0) {
			return 0;
		}

		if (std::is_signed<T>::value) {
			bitwidth = 1;
		} else {
			bitwidth = 0;
		}

		while (value) {
			bitwidth++;
			value >>= 1;
		}

		bitwidth = GetEffectiveWidth<T>(bitwidth);

		// Assert results are correct
#ifdef DEBUG
		if (bitwidth < sizeof(T) * 8 && bitwidth != 0) {
			if (std::is_signed<T>::value) {
				D_ASSERT((int64_t)max_value <= (int64_t)(1L << (bitwidth - 1)) - 1);
				D_ASSERT((int64_t)min_value >= (int64_t)(-1 * ((1L << (bitwidth - 1)) - 1) - 1));
			} else {
				D_ASSERT((uint64_t)max_value <= (uint64_t)(1L << (bitwidth)) - 1);
			}
		}
#endif
		if (round_to_next_byte) {
			return (bitwidth / 8 + (bitwidth % 8 != 0)) * 8;
		} else {
			return bitwidth;
		}
	}

	template <class T>
	static void UnPackGroup(data_ptr_t dst, data_ptr_t src, bitpacking_width_t width,
	                        bool skip_sign_extension = false) {
		if (std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value) {
			duckdb_fastpforlib::fastunpack((const uint8_t *)src, (uint8_t *)dst, (uint32_t)width);
		} else if (std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value) {
			duckdb_fastpforlib::fastunpack((const uint16_t *)src, (uint16_t *)dst, (uint32_t)width);
		} else if (std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value) {
			duckdb_fastpforlib::fastunpack((const uint32_t *)src, (uint32_t *)dst, (uint32_t)width);
		} else if (std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value) {
			duckdb_fastpforlib::fastunpack((const uint32_t *)src, (uint64_t *)dst, (uint32_t)width);
		} else {
			throw InternalException("Unsupported type found in bitpacking.");
		}

		if (NumericLimits<T>::IsSigned() && !skip_sign_extension && width > 0 && width < sizeof(T) * 8) {
			SignExtend<T>(dst, width);
		}
	}

	// Prevent compression at widths that are ineffective
	template <class T>
	static bitpacking_width_t GetEffectiveWidth(bitpacking_width_t width) {
		if (width > 56) {
			return 64;
		}

		if (width > 28 && (std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value)) {
			return 32;
		}

		else if (width > 14 && (std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value)) {
			return 16;
		}

		return width;
	}

	// Sign bit extension
	template <class T, class T_U = typename std::make_unsigned<T>::type>
	static void SignExtend(data_ptr_t dst, bitpacking_width_t width) {
		T const mask = ((T_U)1) << (width - 1);
		for (idx_t i = 0; i < BitpackingPrimitives::BITPACKING_ALGORITHM_GROUP_SIZE; ++i) {
			T value = Load<T>(dst + i * sizeof(T));
			value = value & ((((T_U)1) << width) - ((T_U)1));
			T result = (value ^ mask) - mask;
			Store(result, dst + i * sizeof(T));
		}
	}

	template <class T>
	static void PackGroup(data_ptr_t dst, T *values, bitpacking_width_t width) {
		if (std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value) {
			duckdb_fastpforlib::fastpack((const uint8_t *)values, (uint8_t *)dst, (uint32_t)width);
		} else if (std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value) {
			duckdb_fastpforlib::fastpack((const uint16_t *)values, (uint16_t *)dst, (uint32_t)width);
		} else if (std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value) {
			duckdb_fastpforlib::fastpack((const uint32_t *)values, (uint32_t *)dst, (uint32_t)width);
		} else if (std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value) {
			duckdb_fastpforlib::fastpack((const uint64_t *)values, (uint32_t *)dst, (uint32_t)width);
		} else {
			throw InternalException("Unsupported type found in bitpacking.");
		}
	}
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/column_data_checkpointer.hpp
//
//
//===----------------------------------------------------------------------===//



//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/column_data.hpp
//
//
//===----------------------------------------------------------------------===//










//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/column_checkpoint_state.hpp
//
//
//===----------------------------------------------------------------------===//









namespace duckdb {
class ColumnData;
class DatabaseInstance;
class RowGroup;
class TableDataWriter;

struct ColumnCheckpointState {
	ColumnCheckpointState(RowGroup &row_group, ColumnData &column_data, TableDataWriter &writer);
	virtual ~ColumnCheckpointState();

	RowGroup &row_group;
	ColumnData &column_data;
	TableDataWriter &writer;
	SegmentTree new_tree;
	vector<DataPointer> data_pointers;
	unique_ptr<BaseStatistics> global_stats;

public:
	virtual unique_ptr<BaseStatistics> GetStatistics();

	virtual void FlushSegment(unique_ptr<ColumnSegment> segment, idx_t segment_size);
	virtual void FlushToDisk();
};

} // namespace duckdb



namespace duckdb {
class ColumnData;
class ColumnSegment;
class DatabaseInstance;
class RowGroup;
class TableDataWriter;
class Transaction;

struct DataTableInfo;

struct ColumnCheckpointInfo {
	ColumnCheckpointInfo(CompressionType compression_type_p) : compression_type(compression_type_p) {};
	CompressionType compression_type;
};

class ColumnData {
	friend class ColumnDataCheckpointer;

public:
	ColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type, ColumnData *parent);
	virtual ~ColumnData();

	//! Table info for the column
	DataTableInfo &info;
	//! The column index of the column, either within the parent table or within the parent
	idx_t column_index;
	//! The start row
	idx_t start;
	//! The type of the column
	LogicalType type;
	//! The parent column (if any)
	ColumnData *parent;

public:
	virtual bool CheckZonemap(ColumnScanState &state, TableFilter &filter) = 0;

	DatabaseInstance &GetDatabase() const;
	DataTableInfo &GetTableInfo() const;
	virtual idx_t GetMaxEntry();

	//! The root type of the column
	const LogicalType &RootType() const;

	//! Initialize a scan of the column
	virtual void InitializeScan(ColumnScanState &state);
	//! Initialize a scan starting at the specified offset
	virtual void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx);
	//! Scan the next vector from the column
	virtual idx_t Scan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result);
	virtual idx_t ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates);
	virtual void ScanCommittedRange(idx_t row_group_start, idx_t offset_in_row_group, idx_t count, Vector &result);
	virtual idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count);
	//! Select
	virtual void Select(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
	                    SelectionVector &sel, idx_t &count, const TableFilter &filter);
	virtual void FilterScan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result,
	                        SelectionVector &sel, idx_t count);
	virtual void FilterScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, SelectionVector &sel,
	                                 idx_t count, bool allow_updates);

	//! Skip the scan forward by "count" rows
	virtual void Skip(ColumnScanState &state, idx_t count = STANDARD_VECTOR_SIZE);

	//! Initialize an appending phase for this column
	virtual void InitializeAppend(ColumnAppendState &state);
	//! Append a vector of type [type] to the end of the column
	virtual void Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count);
	virtual void AppendData(BaseStatistics &stats, ColumnAppendState &state, VectorData &vdata, idx_t count);
	//! Revert a set of appends to the ColumnData
	virtual void RevertAppend(row_t start_row);

	//! Fetch the vector from the column data that belongs to this specific row
	virtual idx_t Fetch(ColumnScanState &state, row_t row_id, Vector &result);
	//! Fetch a specific row id and append it to the vector
	virtual void FetchRow(Transaction &transaction, ColumnFetchState &state, row_t row_id, Vector &result,
	                      idx_t result_idx);

	virtual void Update(Transaction &transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
	                    idx_t update_count);
	virtual void UpdateColumn(Transaction &transaction, const vector<column_t> &column_path, Vector &update_vector,
	                          row_t *row_ids, idx_t update_count, idx_t depth);
	virtual unique_ptr<BaseStatistics> GetUpdateStatistics();

	virtual void CommitDropColumn();

	virtual unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, TableDataWriter &writer);
	virtual unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, TableDataWriter &writer,
	                                                     ColumnCheckpointInfo &checkpoint_info);

	virtual void CheckpointScan(ColumnSegment *segment, ColumnScanState &state, idx_t row_group_start, idx_t count,
	                            Vector &scan_vector);

	virtual void DeserializeColumn(Deserializer &source);
	static shared_ptr<ColumnData> Deserialize(DataTableInfo &info, idx_t column_index, idx_t start_row,
	                                          Deserializer &source, const LogicalType &type, ColumnData *parent);

	virtual void GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, vector<vector<Value>> &result);
	virtual void Verify(RowGroup &parent);

	static shared_ptr<ColumnData> CreateColumn(DataTableInfo &info, idx_t column_index, idx_t start_row,
	                                           const LogicalType &type, ColumnData *parent = nullptr);
	static unique_ptr<ColumnData> CreateColumnUnique(DataTableInfo &info, idx_t column_index, idx_t start_row,
	                                                 const LogicalType &type, ColumnData *parent = nullptr);

protected:
	//! Append a transient segment
	void AppendTransientSegment(idx_t start_row);

	//! Scans a base vector from the column
	idx_t ScanVector(ColumnScanState &state, Vector &result, idx_t remaining);
	//! Scans a vector from the column merged with any potential updates
	//! If ALLOW_UPDATES is set to false, the function will instead throw an exception if any updates are found
	template <bool SCAN_COMMITTED, bool ALLOW_UPDATES>
	idx_t ScanVector(Transaction *transaction, idx_t vector_index, ColumnScanState &state, Vector &result);

protected:
	//! The segments holding the data of this column segment
	SegmentTree data;
	//! The lock for the updates
	mutex update_lock;
	//! The updates for this column segment
	unique_ptr<UpdateSegment> updates;
};

} // namespace duckdb



namespace duckdb {

class ColumnDataCheckpointer {
public:
	ColumnDataCheckpointer(ColumnData &col_data_p, RowGroup &row_group_p, ColumnCheckpointState &state_p,
	                       ColumnCheckpointInfo &checkpoint_info);

public:
	DatabaseInstance &GetDatabase();
	const LogicalType &GetType() const;
	ColumnData &GetColumnData();
	RowGroup &GetRowGroup();
	ColumnCheckpointState &GetCheckpointState();

	void Checkpoint(unique_ptr<SegmentBase> segment);

private:
	void ScanSegments(const std::function<void(Vector &, idx_t)> &callback);
	unique_ptr<AnalyzeState> DetectBestCompressionMethod(idx_t &compression_idx);
	void WriteToDisk();
	bool HasChanges();
	void WritePersistentSegments();

private:
	ColumnData &col_data;
	RowGroup &row_group;
	ColumnCheckpointState &state;
	bool is_validity;
	Vector intermediate;
	unique_ptr<SegmentBase> owned_segment;
	vector<CompressionFunction *> compression_functions;
	ColumnCheckpointInfo &checkpoint_info;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/segment/uncompressed.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class DatabaseInstance;

struct UncompressedFunctions {
	static unique_ptr<CompressionState> InitCompression(ColumnDataCheckpointer &checkpointer,
	                                                    unique_ptr<AnalyzeState> state);
	static void Compress(CompressionState &state_p, Vector &data, idx_t count);
	static void FinalizeCompress(CompressionState &state_p);
	static void EmptySkip(ColumnSegment &segment, ColumnScanState &state, idx_t skip_count) {
	}
};

struct FixedSizeUncompressed {
	static CompressionFunction GetFunction(PhysicalType data_type);
};

struct ValidityUncompressed {
public:
	static CompressionFunction GetFunction(PhysicalType data_type);

public:
	static const validity_t LOWER_MASKS[65];
	static const validity_t UPPER_MASKS[65];
};

struct StringUncompressed {
public:
	static CompressionFunction GetFunction(PhysicalType data_type);

public:
	//! The max string size that is allowed within a block. Strings bigger than this will be labeled as a BIG STRING and
	//! offloaded to the overflow blocks.
	static constexpr uint16_t STRING_BLOCK_LIMIT = 4096;
};

} // namespace duckdb
















namespace duckdb {
struct StringDictionaryContainer {
	//! The size of the dictionary
	uint32_t size;
	//! The end of the dictionary (typically Storage::BLOCK_SIZE)
	uint32_t end;

	void Verify() {
		D_ASSERT(size <= Storage::BLOCK_SIZE);
		D_ASSERT(end <= Storage::BLOCK_SIZE);
		D_ASSERT(size <= end);
	}
};

struct StringScanState : public SegmentScanState {
	BufferHandle handle;
};

struct UncompressedStringStorage {
public:
	//! Dictionary header size at the beginning of the string segment (offset + length)
	static constexpr uint16_t DICTIONARY_HEADER_SIZE = sizeof(uint32_t) + sizeof(uint32_t);
	//! Marker used in length field to indicate the presence of a big string
	static constexpr uint16_t BIG_STRING_MARKER = (uint16_t)-1;
	//! Base size of big string marker (block id + offset)
	static constexpr idx_t BIG_STRING_MARKER_BASE_SIZE = sizeof(block_id_t) + sizeof(int32_t);
	//! The marker size of the big string
	static constexpr idx_t BIG_STRING_MARKER_SIZE = BIG_STRING_MARKER_BASE_SIZE;
	//! The size below which the segment is compacted on flushing
	static constexpr size_t COMPACTION_FLUSH_LIMIT = (size_t)Storage::BLOCK_SIZE / 5 * 4;

public:
	static unique_ptr<AnalyzeState> StringInitAnalyze(ColumnData &col_data, PhysicalType type);
	static bool StringAnalyze(AnalyzeState &state_p, Vector &input, idx_t count);
	static idx_t StringFinalAnalyze(AnalyzeState &state_p);
	static unique_ptr<SegmentScanState> StringInitScan(ColumnSegment &segment);
	static void StringScanPartial(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result,
	                              idx_t result_offset);
	static void StringScan(ColumnSegment &segment, ColumnScanState &state, idx_t scan_count, Vector &result);
	static void StringFetchRow(ColumnSegment &segment, ColumnFetchState &state, row_t row_id, Vector &result,
	                           idx_t result_idx);
	static unique_ptr<CompressedSegmentState> StringInitSegment(ColumnSegment &segment, block_id_t block_id);

	static idx_t StringAppend(ColumnSegment &segment, SegmentStatistics &stats, VectorData &data, idx_t offset,
	                          idx_t count) {
		return StringAppendBase(segment, stats, data, offset, count);
	}

	template <bool DUPLICATE_ELIMINATE = false>
	static idx_t StringAppendBase(ColumnSegment &segment, SegmentStatistics &stats, VectorData &data, idx_t offset,
	                              idx_t count, std::unordered_map<string, int32_t> *seen_strings = nullptr) {
		auto &buffer_manager = BufferManager::GetBufferManager(segment.db);
		auto handle = buffer_manager.Pin(segment.block);

		D_ASSERT(segment.GetBlockOffset() == 0);
		auto source_data = (string_t *)data.data;
		auto result_data = (int32_t *)(handle.Ptr() + DICTIONARY_HEADER_SIZE);
		for (idx_t i = 0; i < count; i++) {
			auto source_idx = data.sel->get_index(offset + i);
			auto target_idx = segment.count.load();
			idx_t remaining_space = RemainingSpace(segment, handle);
			if (remaining_space < sizeof(int32_t)) {
				// string index does not fit in the block at all
				return i;
			}
			remaining_space -= sizeof(int32_t);
			auto dictionary = GetDictionary(segment, handle);
			if (!data.validity.RowIsValid(source_idx)) {
				// null value is stored as a copy of the last value, this is done to be able to efficiently do the
				// string_length calculation
				if (target_idx > 0) {
					result_data[target_idx] = result_data[target_idx - 1];
				} else {
					result_data[target_idx] = 0;
				}
			} else {
				auto end = handle.Ptr() + dictionary.end;

				dictionary.Verify();

				int32_t match;
				bool found;
				if (DUPLICATE_ELIMINATE) {
					auto search = seen_strings->find(source_data[source_idx].GetString());
					if (search != seen_strings->end()) {
						match = search->second;
						found = true;
					} else {
						found = false;
					}
				}

				if (DUPLICATE_ELIMINATE && found) {
					// We have seen this string
					result_data[target_idx] = match;
				} else {
					// Unknown string, continue
					// non-null value, check if we can fit it within the block
					idx_t string_length = source_data[source_idx].GetSize();
					idx_t dictionary_length = string_length;

					// determine whether or not we have space in the block for this string
					bool use_overflow_block = false;
					idx_t required_space = dictionary_length;
					if (required_space >= StringUncompressed::STRING_BLOCK_LIMIT) {
						// string exceeds block limit, store in overflow block and only write a marker here
						required_space = BIG_STRING_MARKER_SIZE;
						use_overflow_block = true;
					}
					if (required_space > remaining_space) {
						// no space remaining: return how many tuples we ended up writing
						return i;
					}

					// we have space: write the string
					UpdateStringStats(stats, source_data[source_idx]);

					if (use_overflow_block) {
						// write to overflow blocks
						block_id_t block;
						int32_t offset;
						// write the string into the current string block
						WriteString(segment, source_data[source_idx], block, offset);
						dictionary.size += BIG_STRING_MARKER_SIZE;
						auto dict_pos = end - dictionary.size;

						// write a big string marker into the dictionary
						WriteStringMarker(dict_pos, block, offset);
					} else {
						// string fits in block, append to dictionary and increment dictionary position
						D_ASSERT(string_length < NumericLimits<uint16_t>::Maximum());
						dictionary.size += required_space;
						auto dict_pos = end - dictionary.size;
						// now write the actual string data into the dictionary
						memcpy(dict_pos, source_data[source_idx].GetDataUnsafe(), string_length);
					}
					D_ASSERT(RemainingSpace(segment, handle) <= Storage::BLOCK_SIZE);
					// place the dictionary offset into the set of vectors
					dictionary.Verify();

					// note: for overflow strings we write negative value
					result_data[target_idx] = use_overflow_block ? -1 * dictionary.size : dictionary.size;

					if (DUPLICATE_ELIMINATE) {
						seen_strings->insert({source_data[source_idx].GetString(), dictionary.size});
					}
					SetDictionary(segment, handle, dictionary);
				}
			}
			segment.count++;
		}
		return count;
	}

	static idx_t FinalizeAppend(ColumnSegment &segment, SegmentStatistics &stats);

public:
	static inline void UpdateStringStats(SegmentStatistics &stats, const string_t &new_value) {
		auto &sstats = (StringStatistics &)*stats.statistics;
		sstats.Update(new_value);
	}

	static void SetDictionary(ColumnSegment &segment, BufferHandle &handle, StringDictionaryContainer dict);
	static StringDictionaryContainer GetDictionary(ColumnSegment &segment, BufferHandle &handle);
	static idx_t RemainingSpace(ColumnSegment &segment, BufferHandle &handle);
	static void WriteString(ColumnSegment &segment, string_t string, block_id_t &result_block, int32_t &result_offset);
	static void WriteStringMemory(ColumnSegment &segment, string_t string, block_id_t &result_block,
	                              int32_t &result_offset);
	static string_t ReadOverflowString(ColumnSegment &segment, Vector &result, block_id_t block, int32_t offset);
	static string_t ReadString(data_ptr_t target, int32_t offset, uint32_t string_length);
	static string_t ReadStringWithLength(data_ptr_t target, int32_t offset);
	static void WriteStringMarker(data_ptr_t target, block_id_t block_id, int32_t offset);
	static void ReadStringMarker(data_ptr_t target, block_id_t &block_id, int32_t &offset);

	static string_location_t FetchStringLocation(StringDictionaryContainer dict, data_ptr_t baseptr,
	                                             int32_t dict_offset);
	static string_t FetchStringFromDict(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result,
	                                    data_ptr_t baseptr, int32_t dict_offset, uint32_t string_length);
	static string_t FetchString(ColumnSegment &segment, StringDictionaryContainer dict, Vector &result,
	                            data_ptr_t baseptr, string_location_t location, uint32_t string_length);
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/standard_column_data.hpp
//
//
//===----------------------------------------------------------------------===//




//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/validity_column_data.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {

//! Validity column data represents the validity data (i.e. which values are null)
class ValidityColumnData : public ColumnData {
public:
	ValidityColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, ColumnData *parent);

public:
	bool CheckZonemap(ColumnScanState &state, TableFilter &filter) override;
};

} // namespace duckdb


namespace duckdb {

//! Standard column data represents a regular flat column (e.g. a column of type INTEGER or STRING)
class StandardColumnData : public ColumnData {
public:
	StandardColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type,
	                   ColumnData *parent = nullptr);

	//! The validity column data
	ValidityColumnData validity;

public:
	bool CheckZonemap(ColumnScanState &state, TableFilter &filter) override;

	void InitializeScan(ColumnScanState &state) override;
	void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) override;

	idx_t Scan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result) override;
	idx_t ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates) override;
	idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count) override;

	void InitializeAppend(ColumnAppendState &state) override;
	void AppendData(BaseStatistics &stats, ColumnAppendState &state, VectorData &vdata, idx_t count) override;
	void RevertAppend(row_t start_row) override;
	idx_t Fetch(ColumnScanState &state, row_t row_id, Vector &result) override;
	void FetchRow(Transaction &transaction, ColumnFetchState &state, row_t row_id, Vector &result,
	              idx_t result_idx) override;
	void Update(Transaction &transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
	            idx_t update_count) override;
	void UpdateColumn(Transaction &transaction, const vector<column_t> &column_path, Vector &update_vector,
	                  row_t *row_ids, idx_t update_count, idx_t depth) override;
	unique_ptr<BaseStatistics> GetUpdateStatistics() override;

	void CommitDropColumn() override;

	unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, TableDataWriter &writer) override;
	unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, TableDataWriter &writer,
	                                             ColumnCheckpointInfo &checkpoint_info) override;
	void CheckpointScan(ColumnSegment *segment, ColumnScanState &state, idx_t row_group_start, idx_t count,
	                    Vector &scan_vector) override;

	void DeserializeColumn(Deserializer &source) override;

	void GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, vector<vector<Value>> &result) override;

	void Verify(RowGroup &parent) override;

private:
	template <bool SCAN_COMMITTED, bool ALLOW_UPDATES>
	void TemplatedScan(Transaction *transaction, ColumnScanState &state, Vector &result);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/single_file_block_manager.hpp
//
//
//===----------------------------------------------------------------------===//











namespace duckdb {
class DatabaseInstance;

//! SingleFileBlockManager is an implementation for a BlockManager which manages blocks in a single file
class SingleFileBlockManager : public BlockManager {
	//! The location in the file where the block writing starts
	static constexpr uint64_t BLOCK_START = Storage::FILE_HEADER_SIZE * 3;

public:
	SingleFileBlockManager(DatabaseInstance &db, string path, bool read_only, bool create_new, bool use_direct_io);

	void StartCheckpoint() override;
	//! Creates a new Block using the specified block_id and returns a pointer
	unique_ptr<Block> CreateBlock(block_id_t block_id) override;
	//! Return the next free block id
	block_id_t GetFreeBlockId() override;
	//! Returns whether or not a specified block is the root block
	bool IsRootBlock(block_id_t root) override;
	//! Mark a block as modified
	void MarkBlockAsModified(block_id_t block_id) override;
	//! Increase the reference count of a block. The block should hold at least one reference
	void IncreaseBlockReferenceCount(block_id_t block_id) override;
	//! Return the meta block id
	block_id_t GetMetaBlock() override;
	//! Read the content of the block from disk
	void Read(Block &block) override;
	//! Write the given block to disk
	void Write(FileBuffer &block, block_id_t block_id) override;
	//! Write the header to disk, this is the final step of the checkpointing process
	void WriteHeader(DatabaseHeader header) override;

	//! Returns the number of total blocks
	idx_t TotalBlocks() override {
		return max_block;
	}
	//! Returns the number of free blocks
	idx_t FreeBlocks() override {
		return free_list.size();
	}
	//! Load the free list from the file
	void LoadFreeList();

private:
	void Initialize(DatabaseHeader &header);

	//! Return the blocks to which we will write the free list and modified blocks
	vector<block_id_t> GetFreeListBlocks();

private:
	DatabaseInstance &db;
	//! The active DatabaseHeader, either 0 (h1) or 1 (h2)
	uint8_t active_header;
	//! The path where the file is stored
	string path;
	//! The file handle
	unique_ptr<FileHandle> handle;
	//! The buffer used to read/write to the headers
	FileBuffer header_buffer;
	//! The list of free blocks that can be written to currently
	set<block_id_t> free_list;
	//! The list of multi-use blocks (i.e. blocks that have >1 reference in the file)
	//! When a multi-use block is marked as modified, the reference count is decreased by 1 instead of directly
	//! Appending the block to the modified_blocks list
	unordered_map<block_id_t, uint32_t> multi_use_blocks;
	//! The list of blocks that will be added to the free list
	unordered_set<block_id_t> modified_blocks;
	//! The current meta block id
	block_id_t meta_block;
	//! The current maximum block id, this id will be given away first after the free_list runs out
	block_id_t max_block;
	//! The block id where the free list can be found
	block_id_t free_list_id;
	//! The current header iteration count
	uint64_t iteration_count;
	//! Whether or not the db is opened in read-only mode
	bool read_only;
	//! Whether or not to use Direct IO to read the blocks
	bool use_direct_io;
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/in_memory_block_manager.hpp
//
//
//===----------------------------------------------------------------------===//







namespace duckdb {

//! InMemoryBlockManager is an implementation for a BlockManager
class InMemoryBlockManager : public BlockManager {
public:
	// LCOV_EXCL_START
	void StartCheckpoint() override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	unique_ptr<Block> CreateBlock(block_id_t block_id) override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	block_id_t GetFreeBlockId() override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	bool IsRootBlock(block_id_t root) override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	void MarkBlockAsModified(block_id_t block_id) override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	void IncreaseBlockReferenceCount(block_id_t block_id) override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	block_id_t GetMetaBlock() override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	void Read(Block &block) override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	void Write(FileBuffer &block, block_id_t block_id) override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	void WriteHeader(DatabaseHeader header) override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	idx_t TotalBlocks() override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	idx_t FreeBlocks() override {
		throw InternalException("Cannot perform IO in in-memory database!");
	}
	// LCOV_EXCL_STOP
};
} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/list_column_data.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! List column data represents a list
class ListColumnData : public ColumnData {
public:
	ListColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type,
	               ColumnData *parent = nullptr);

	//! The child-column of the list
	unique_ptr<ColumnData> child_column;
	//! The validity column data of the struct
	ValidityColumnData validity;

public:
	bool CheckZonemap(ColumnScanState &state, TableFilter &filter) override;

	void InitializeScan(ColumnScanState &state) override;
	void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) override;

	idx_t Scan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result) override;
	idx_t ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates) override;
	idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count) override;

	void Skip(ColumnScanState &state, idx_t count = STANDARD_VECTOR_SIZE) override;

	void InitializeAppend(ColumnAppendState &state) override;
	void Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count) override;
	void RevertAppend(row_t start_row) override;
	idx_t Fetch(ColumnScanState &state, row_t row_id, Vector &result) override;
	void FetchRow(Transaction &transaction, ColumnFetchState &state, row_t row_id, Vector &result,
	              idx_t result_idx) override;
	void Update(Transaction &transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
	            idx_t update_count) override;
	void UpdateColumn(Transaction &transaction, const vector<column_t> &column_path, Vector &update_vector,
	                  row_t *row_ids, idx_t update_count, idx_t depth) override;
	unique_ptr<BaseStatistics> GetUpdateStatistics() override;

	void CommitDropColumn() override;

	unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, TableDataWriter &writer) override;
	unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, TableDataWriter &writer,
	                                             ColumnCheckpointInfo &checkpoint_info) override;

	void DeserializeColumn(Deserializer &source) override;

	void GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, vector<vector<Value>> &result) override;

private:
	list_entry_t FetchListEntry(idx_t row_idx);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/struct_column_data.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {

//! Struct column data represents a struct
class StructColumnData : public ColumnData {
public:
	StructColumnData(DataTableInfo &info, idx_t column_index, idx_t start_row, LogicalType type,
	                 ColumnData *parent = nullptr);

	//! The sub-columns of the struct
	vector<unique_ptr<ColumnData>> sub_columns;
	//! The validity column data of the struct
	ValidityColumnData validity;

public:
	bool CheckZonemap(ColumnScanState &state, TableFilter &filter) override;
	idx_t GetMaxEntry() override;

	void InitializeScan(ColumnScanState &state) override;
	void InitializeScanWithOffset(ColumnScanState &state, idx_t row_idx) override;

	idx_t Scan(Transaction &transaction, idx_t vector_index, ColumnScanState &state, Vector &result) override;
	idx_t ScanCommitted(idx_t vector_index, ColumnScanState &state, Vector &result, bool allow_updates) override;
	idx_t ScanCount(ColumnScanState &state, Vector &result, idx_t count) override;

	void InitializeAppend(ColumnAppendState &state) override;
	void Append(BaseStatistics &stats, ColumnAppendState &state, Vector &vector, idx_t count) override;
	void RevertAppend(row_t start_row) override;
	idx_t Fetch(ColumnScanState &state, row_t row_id, Vector &result) override;
	void FetchRow(Transaction &transaction, ColumnFetchState &state, row_t row_id, Vector &result,
	              idx_t result_idx) override;
	void Update(Transaction &transaction, idx_t column_index, Vector &update_vector, row_t *row_ids,
	            idx_t update_count) override;
	void UpdateColumn(Transaction &transaction, const vector<column_t> &column_path, Vector &update_vector,
	                  row_t *row_ids, idx_t update_count, idx_t depth) override;
	unique_ptr<BaseStatistics> GetUpdateStatistics() override;

	void CommitDropColumn() override;

	unique_ptr<ColumnCheckpointState> CreateCheckpointState(RowGroup &row_group, TableDataWriter &writer) override;
	unique_ptr<ColumnCheckpointState> Checkpoint(RowGroup &row_group, TableDataWriter &writer,
	                                             ColumnCheckpointInfo &checkpoint_info) override;

	void DeserializeColumn(Deserializer &source) override;

	void GetStorageInfo(idx_t row_group_index, vector<idx_t> col_path, vector<vector<Value>> &result) override;

	void Verify(RowGroup &parent) override;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/storage/table/update_segment.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
class ColumnData;
class DataTable;
class Vector;
struct UpdateInfo;
struct UpdateNode;

class UpdateSegment {
public:
	UpdateSegment(ColumnData &column_data);
	~UpdateSegment();

	ColumnData &column_data;

public:
	bool HasUpdates() const;
	bool HasUncommittedUpdates(idx_t vector_index);
	bool HasUpdates(idx_t vector_index) const;
	bool HasUpdates(idx_t start_row_idx, idx_t end_row_idx);
	void ClearUpdates();

	void FetchUpdates(Transaction &transaction, idx_t vector_index, Vector &result);
	void FetchCommitted(idx_t vector_index, Vector &result);
	void FetchCommittedRange(idx_t start_row, idx_t count, Vector &result);
	void Update(Transaction &transaction, idx_t column_index, Vector &update, row_t *ids, idx_t count,
	            Vector &base_data);
	void FetchRow(Transaction &transaction, idx_t row_id, Vector &result, idx_t result_idx);

	void RollbackUpdate(UpdateInfo *info);
	void CleanupUpdateInternal(const StorageLockKey &lock, UpdateInfo *info);
	void CleanupUpdate(UpdateInfo *info);

	unique_ptr<BaseStatistics> GetStatistics();
	StringHeap &GetStringHeap() {
		return heap;
	}

private:
	//! The lock for the update segment
	StorageLock lock;
	//! The root node (if any)
	unique_ptr<UpdateNode> root;
	//! Update statistics
	SegmentStatistics stats;
	//! Stats lock
	mutex stats_lock;
	//! Internal type size
	idx_t type_size;
	//! String heap, only used for strings
	StringHeap heap;

public:
	typedef void (*initialize_update_function_t)(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info,
	                                             Vector &update, const SelectionVector &sel);
	typedef void (*merge_update_function_t)(UpdateInfo *base_info, Vector &base_data, UpdateInfo *update_info,
	                                        Vector &update, row_t *ids, idx_t count, const SelectionVector &sel);
	typedef void (*fetch_update_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info,
	                                        Vector &result);
	typedef void (*fetch_committed_function_t)(UpdateInfo *info, Vector &result);
	typedef void (*fetch_committed_range_function_t)(UpdateInfo *info, idx_t start, idx_t end, idx_t result_offset,
	                                                 Vector &result);
	typedef void (*fetch_row_function_t)(transaction_t start_time, transaction_t transaction_id, UpdateInfo *info,
	                                     idx_t row_idx, Vector &result, idx_t result_idx);
	typedef void (*rollback_update_function_t)(UpdateInfo *base_info, UpdateInfo *rollback_info);
	typedef idx_t (*statistics_update_function_t)(UpdateSegment *segment, SegmentStatistics &stats, Vector &update,
	                                              idx_t count, SelectionVector &sel);

private:
	initialize_update_function_t initialize_update_function;
	merge_update_function_t merge_update_function;
	fetch_update_function_t fetch_update_function;
	fetch_committed_function_t fetch_committed_function;
	fetch_committed_range_function_t fetch_committed_range;
	fetch_row_function_t fetch_row_function;
	rollback_update_function_t rollback_update_function;
	statistics_update_function_t statistics_update_function;

private:
	void InitializeUpdateInfo(UpdateInfo &info, row_t *ids, const SelectionVector &sel, idx_t count, idx_t vector_index,
	                          idx_t vector_offset);
};

struct UpdateNodeData {
	unique_ptr<UpdateInfo> info;
	unique_ptr<sel_t[]> tuples;
	unique_ptr<data_t[]> tuple_data;
};

struct UpdateNode {
	unique_ptr<UpdateNodeData> info[RowGroup::ROW_GROUP_VECTOR_COUNT];
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/update_info.hpp
//
//
//===----------------------------------------------------------------------===//








namespace duckdb {
class UpdateSegment;
struct DataTableInfo;

struct UpdateInfo {
	//! The update segment that this update info affects
	UpdateSegment *segment;
	//! The column index of which column we are updating
	idx_t column_index;
	//! The version number
	atomic<transaction_t> version_number;
	//! The vector index within the uncompressed segment
	idx_t vector_index;
	//! The amount of updated tuples
	sel_t N;
	//! The maximum amount of tuples that can fit into this UpdateInfo
	sel_t max;
	//! The row ids of the tuples that have been updated. This should always be kept sorted!
	sel_t *tuples;
	//! The data of the tuples
	data_ptr_t tuple_data;
	//! The previous update info (or nullptr if it is the base)
	UpdateInfo *prev;
	//! The next update info in the chain (or nullptr if it is the last)
	UpdateInfo *next;

	//! Loop over the update chain and execute the specified callback on all UpdateInfo's that are relevant for that
	//! transaction in-order of newest to oldest
	template <class T>
	static void UpdatesForTransaction(UpdateInfo *current, transaction_t start_time, transaction_t transaction_id,
	                                  T &&callback) {
		while (current) {
			if (current->version_number > start_time && current->version_number != transaction_id) {
				// these tuples were either committed AFTER this transaction started or are not committed yet, use
				// tuples stored in this version
				callback(current);
			}
			current = current->next;
		}
	}

	Value GetValue(idx_t index);
	string ToString();
	void Print();
	void Verify();
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/cleanup_state.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class DataTable;

struct DeleteInfo;
struct UpdateInfo;

class CleanupState {
public:
	CleanupState();
	~CleanupState();

public:
	void CleanupEntry(UndoFlags type, data_ptr_t data);

private:
	// data for index cleanup
	DataTable *current_table;
	DataChunk chunk;
	row_t row_numbers[STANDARD_VECTOR_SIZE];
	idx_t count;

private:
	void CleanupDelete(DeleteInfo *info);
	void CleanupUpdate(UpdateInfo *info);

	void Flush();
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/delete_info.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class ChunkVectorInfo;
class DataTable;

struct DeleteInfo {
	DataTable *table;
	ChunkVectorInfo *vinfo;
	idx_t count;
	idx_t base_row;
	row_t rows[1];
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/commit_state.hpp
//
//
//===----------------------------------------------------------------------===//






namespace duckdb {
class CatalogEntry;
class DataChunk;
class WriteAheadLog;

struct DataTableInfo;
struct DeleteInfo;
struct UpdateInfo;

class CommitState {
public:
	explicit CommitState(transaction_t commit_id, WriteAheadLog *log = nullptr);

	WriteAheadLog *log;
	transaction_t commit_id;
	UndoFlags current_op;

	DataTableInfo *current_table_info;
	idx_t row_identifiers[STANDARD_VECTOR_SIZE];

	unique_ptr<DataChunk> delete_chunk;
	unique_ptr<DataChunk> update_chunk;

public:
	template <bool HAS_LOG>
	void CommitEntry(UndoFlags type, data_ptr_t data);
	void RevertCommit(UndoFlags type, data_ptr_t data);

private:
	void SwitchTable(DataTableInfo *table, UndoFlags new_op);

	void WriteCatalogEntry(CatalogEntry *entry, data_ptr_t extra_data);
	void WriteDelete(DeleteInfo *info);
	void WriteUpdate(UpdateInfo *info);

	void AppendRowId(row_t rowid);
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/append_info.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class DataTable;

struct AppendInfo {
	DataTable *table;
	idx_t start_row;
	idx_t count;
};

} // namespace duckdb
//===----------------------------------------------------------------------===//
//                         DuckDB
//
// duckdb/transaction/rollback_state.hpp
//
//
//===----------------------------------------------------------------------===//





namespace duckdb {
class DataChunk;
class DataTable;
class WriteAheadLog;

class RollbackState {
public:
	RollbackState() {
	}

public:
	void RollbackEntry(UndoFlags type, data_ptr_t data);
};

} // namespace duckdb
